From 354f39831cbd2e0cbfff6d182b0d8dd98653bcbf Mon Sep 17 00:00:00 2001 From: BenjaminLu Date: Thu, 14 Sep 2023 01:00:35 +0800 Subject: [PATCH 1/4] fix: refactoring tests --- src/handler/newOrder.ts | 4 +- src/signer/pmmv5.ts | 2 +- src/signer/rfqv2.ts | 2 - test/amm.spec.ts | 159 +++ test/new_order.spec.ts | 1476 ---------------------------- test/pmm.spec.ts | 191 ++++ test/rfqv1.spec.ts | 270 +++++ test/rfqv2.spec.ts | 255 +++++ test/utils.ts | 241 +++++ test/{ => utils}/numbers.spec.ts | 2 +- test/{ => utils}/quoting.spec.ts | 2 +- test/{ => utils}/utils.spec.ts | 12 +- test/{ => utils}/validator.spec.ts | 11 +- 13 files changed, 1132 insertions(+), 1495 deletions(-) create mode 100644 test/amm.spec.ts delete mode 100644 test/new_order.spec.ts create mode 100644 test/pmm.spec.ts create mode 100644 test/rfqv1.spec.ts create mode 100644 test/rfqv2.spec.ts create mode 100644 test/utils.ts rename test/{ => utils}/numbers.spec.ts (91%) rename test/{ => utils}/quoting.spec.ts (78%) rename test/{ => utils}/utils.spec.ts (91%) rename test/{ => utils}/validator.spec.ts (55%) diff --git a/src/handler/newOrder.ts b/src/handler/newOrder.ts index 0702470..257d2e8 100644 --- a/src/handler/newOrder.ts +++ b/src/handler/newOrder.ts @@ -63,7 +63,7 @@ export interface Order { payload?: string } -interface Response { +export interface Response { rate: NumberOrString minAmount: NumberOrString maxAmount: NumberOrString @@ -205,7 +205,7 @@ const _getBaseTokenByAddress = (baseTokenAddr, tokenList) => { const getBaseTokenByAddress = memoize(_getBaseTokenByAddress) -export const newOrder = async (ctx) => { +export const newOrder = async (ctx): Promise => { const { quoter, signer, chainID, walletType, signingUrl, permitType } = ctx const req: QueryInterface = { protocol: Protocol.PMMV5, // by default is v2 protocol diff --git a/src/signer/pmmv5.ts b/src/signer/pmmv5.ts index 6aef7e1..9c6a343 100644 --- a/src/signer/pmmv5.ts +++ b/src/signer/pmmv5.ts @@ -14,7 +14,7 @@ import { Protocol } from '../types' import { ExtendedZXOrder, RemoteSigningPMMV5Request } from './types' import { Order as ZXOrder } from '0x-v2-order-utils' -const EIP712_ORDER_SCHEMA = { +export const EIP712_ORDER_SCHEMA = { name: 'Order', parameters: [ { name: 'makerAddress', type: EIP712Types.Address }, diff --git a/src/signer/rfqv2.ts b/src/signer/rfqv2.ts index ee3576e..8e14192 100644 --- a/src/signer/rfqv2.ts +++ b/src/signer/rfqv2.ts @@ -163,8 +163,6 @@ export const buildSignedOrder = async ( const orderHash = getOfferHash(rfqOrder) console.log(`orderHash: ${orderHash}`) const orderSignDigest = getOfferSignDigest(rfqOrder, chainId, rfqAddr) - console.log(`chainId: ${chainId}`) - console.log(`rfqAddr: ${rfqAddr}`) console.log(`orderSignDigest: ${orderSignDigest}`) let makerWalletSignature if (!signingUrl) { diff --git a/test/amm.spec.ts b/test/amm.spec.ts new file mode 100644 index 0000000..f88c41e --- /dev/null +++ b/test/amm.spec.ts @@ -0,0 +1,159 @@ +import { ethers, network } from 'hardhat' +import { Wallet, utils } from 'ethers' +import { Protocol } from '../src/types' +import { WalletType } from '../src/signer/types' +import * as ethUtils from 'ethereumjs-util' +import { WETH } from '@tokenlon/sdk' +import { expect } from 'chai' +import { generateSaltWithFeeFactor } from '../src/signer/pmmv5' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { USDT_ADDRESS, callNewOrder, init } from './utils' + +describe('AMM NewOrder', function () { + const chainId: number = network.config.chainId! + let signer: SignerWithAddress + before(async () => { + const signers = await ethers.getSigners() + signer = signers[0] + }) + beforeEach(() => { + init(chainId, signer) + }) + it('should create ammv1 order by uniswap v2', async function () { + const ammAddr = '0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852' + const order = await callNewOrder({ + chainId: chainId, + base: 'ETH', + quote: 'USDT', + side: 'SELL', + amount: 0.1, + signer, + userAddr: Wallet.createRandom().address.toLowerCase(), + protocol: Protocol.AMMV1, + makerAddress: ammAddr, + }) + 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') + expect(order.makerAddress).eq('0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852') + expect(order.makerAssetAmount).eq('100000') + expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) + expect(order.makerAssetData).eq( + `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` + ) + expect(order.takerAddress).eq('0x25657705a6be20511687d483f2fccfb2d92f6033') + expect(order.takerAssetAmount).eq('100000000000000000') + expect(order.takerAssetAddress).eq('0x0000000000000000000000000000000000000000') + expect(order.takerAssetData).eq( + '0xf47261b00000000000000000000000000000000000000000000000000000000000000000' + ) + expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') + expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') + expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') + // The following fields are to be compatible `Order` struct. + expect(order.makerFee).eq('0') + expect(order.takerFee).eq('0') + // verify signature length, the signature is generated ramdonly. + expect(order.makerWalletSignature?.length).eq(40) + // verify random values + expect(order.salt?.toString().length).gt(0) + expect(Number(order.expirationTimeSeconds)).gt(0) + }) + it('should create ammv2 order by uniswap v2', async function () { + const ammAddr = '0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852' + const payload = Buffer.from( + JSON.stringify({ + path: [WETH[chainId].toLowerCase(), USDT_ADDRESS[chainId].toLowerCase()], + }) + ).toString('base64') + const order = await callNewOrder({ + chainId: chainId, + base: 'ETH', + quote: 'USDT', + side: 'SELL', + amount: 0.1, + signer, + userAddr: Wallet.createRandom().address.toLowerCase(), + protocol: Protocol.AMMV2, + makerAddress: ammAddr, + payload: payload, + }) + expect(order).is.not.null + expect(order.protocol).eq(Protocol.AMMV2) + expect(order.quoteId).eq('1--echo-testing-8888') + expect(order.makerAddress).eq('0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852') + expect(order.makerAssetAmount).eq('100000') + expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) + expect(order.makerAssetData).eq( + `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` + ) + expect(order.takerAddress).eq('0x25657705a6be20511687d483f2fccfb2d92f6033') + expect(order.takerAssetAmount).eq('100000000000000000') + expect(order.takerAssetAddress).eq('0x0000000000000000000000000000000000000000') + expect(order.takerAssetData).eq( + '0xf47261b00000000000000000000000000000000000000000000000000000000000000000' + ) + expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') + expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') + expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') + // The following fields are to be compatible `Order` struct. + expect(order.makerFee).eq('0') + expect(order.takerFee).eq('0') + // verify signature length, the signature is generated ramdonly. + expect(order.makerWalletSignature?.length).eq(40) + // verify random values + expect(order.salt?.toString().length).gt(0) + expect(Number(order.expirationTimeSeconds)).gt(0) + expect(order.payload).eq(payload) + }) + describe('handle token precision and decimals', () => { + it('should format taker asset amount', async function () { + const order = await callNewOrder({ + chainId: chainId, + base: 'ETH', + quote: 'USDT', + side: 'BUY', + amount: 0.1111, + walletType: WalletType.MMP_VERSION_4, + signer: Wallet.createRandom(), + userAddr: Wallet.createRandom().address.toLowerCase(), + protocol: Protocol.PMMV5, + }) + expect(order).is.not.null + expect(order.quoteId).eq('1--echo-testing-8888') + expect(order.makerWalletSignature?.toString().slice(-1)).eq('4') + expect(order.takerAssetData.slice(34)).eq(USDT_ADDRESS[chainId].toLowerCase().slice(2)) + expect(order.takerAssetAmount).eq(utils.parseUnits('0.1114', 6).toString()) + expect(order.makerAssetAmount).eq(utils.parseEther('0.1114').toString()) + }) + it('should format maker asset amount', async function () { + const order = await callNewOrder({ + chainId: chainId, + base: 'ETH', + quote: 'USDT', + side: 'SELL', + amount: 0.1111, + walletType: WalletType.MMP_VERSION_4, + signer: Wallet.createRandom(), + userAddr: Wallet.createRandom().address.toLowerCase(), + protocol: Protocol.PMMV5, + }) + expect(order).is.not.null + expect(order.quoteId).eq('1--echo-testing-8888') + expect(order.makerWalletSignature?.slice(-1)).eq('4') + expect(order.takerAssetAmount).eq(utils.parseEther('0.1111').toString()) + expect(order.makerAssetAmount).eq(utils.parseUnits('0.1111', 6).toString()) + }) + }) + 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(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/new_order.spec.ts b/test/new_order.spec.ts deleted file mode 100644 index fa48e15..0000000 --- a/test/new_order.spec.ts +++ /dev/null @@ -1,1476 +0,0 @@ -import { ethers, network } from 'hardhat' -import { Wallet, utils, Contract } from 'ethers' -import { newOrder } from '../src/handler' -import { updaterStack, Updater } from '../src/worker' -import { NULL_ADDRESS } from '../src/constants' -import { Protocol } from '../src/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, 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' -import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' - -const RFQV2: Record = { - 1: '0x91C986709Bb4fE0763edF8E2690EE9d5019Bea4a', - 5: '0xaE5FDd548E5B107C54E5c0D36952fB8a089f10C7', -} - -const RFQV1: Record = { - 1: '0xfD6C2d2499b1331101726A8AC68CCc9Da3fAB54F', - 5: '0x117CAf73eB142eDC431E707DC33D4dfeF7c5BAd0', -} - -const usdtHolders = { - 1: '0x15abb66bA754F05cBC0165A64A11cDed1543dE48', - 5: '0x031BBFB9379c4e6E3F42fb93a9f09C060c7fA037', -} - -const USDT_ADDRESS: Record = { - 1: '0xdac17f958d2ee523a2206206994597c13d831ec7', - 5: '0xa93ef9215b907c19e739e2214e1aa5412a0401b5', -} - -const replaceMarketMakingAddress = (chainId: number, address: string, updaterStack) => { - const mockMarkerMakerConfigUpdater = new Updater({ - name: 'mockMarkerMakerConfigUpdater', - updater() { - return Promise.resolve({}) - }, - }) - const cacheResult = { - mmId: 1, - mmProxyContractAddress: address.toLowerCase(), - tokenlonExchangeContractAddress: '0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491', - exchangeContractAddress: '0x30589010550762d2f0d06f650d8e8b6ade6dbf4b', - userProxyContractAddress: '0x25657705a6be20511687d483f2fccfb2d92f6033', - wethContractAddress: WETH[chainId].toLowerCase(), - orderExpirationSeconds: 600, - feeFactor: 30, - addressBookV5: { - Tokenlon: '0x085966eE3E32A0Da16467569512535D38626B547', - PMM: '0x7bd7d025D4231aAD1233967b527FFd7416410257', - AMMWrapper: '0xCF011536f10e85e376E70905EED4CA9eA8Cded34', - RFQ: RFQV1[chainId], - RFQV2: RFQV2[chainId], - }, - } - mockMarkerMakerConfigUpdater.cacheResult = cacheResult - updaterStack['markerMakerConfigUpdater'] = mockMarkerMakerConfigUpdater -} - -describe('NewOrder', function () { - const chainId: number = network.config.chainId - let signer: SignerWithAddress - let rfqv1: Contract - let rfqv2: Contract - before(async () => { - const signers = await ethers.getSigners() - signer = signers[0] - const usdtHolderAddr = usdtHolders[chainId] - rfqv1 = await ethers.getContractAt('ISignatureValidator', RFQV1[chainId]) - rfqv2 = await ethers.getContractAt('ISignatureValidator', RFQV2[chainId]) - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [usdtHolderAddr], - }) - }) - beforeEach(function () { - const mockMarkerMakerConfigUpdater = new Updater({ - name: 'mockMarkerMakerConfigUpdater', - updater() { - return Promise.resolve({}) - }, - }) - mockMarkerMakerConfigUpdater.cacheResult = { - mmId: 1, - mmProxyContractAddress: signer.address.toLowerCase(), - tokenlonExchangeContractAddress: '0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491', - exchangeContractAddress: '0x30589010550762d2f0d06f650d8e8b6ade6dbf4b', - userProxyContractAddress: '0x25657705a6be20511687d483f2fccfb2d92f6033', - wethContractAddress: WETH[chainId].toLowerCase(), - orderExpirationSeconds: 600, - feeFactor: 30, - addressBookV5: { - Tokenlon: '0x085966eE3E32A0Da16467569512535D38626B547', - PMM: '0x7bd7d025D4231aAD1233967b527FFd7416410257', - AMMWrapper: '0xCF011536f10e85e376E70905EED4CA9eA8Cded34', - RFQ: RFQV1[chainId], - RFQV2: RFQV2[chainId], - }, - } - const mockTokenConfigsFromImtokenUpdater = new Updater({ - name: 'mockTokenConfigsFromImtokenUpdater', - updater() { - return Promise.resolve({}) - }, - }) - mockTokenConfigsFromImtokenUpdater.cacheResult = [] - const mockTokenListUpdate = new Updater({ - name: 'mockTokenListUpdate', - updater() { - return Promise.resolve({}) - }, - }) - mockTokenListUpdate.cacheResult = [ - { - symbol: 'ETH', - contractAddress: NULL_ADDRESS, - decimal: 18, - precision: 4, - minTradeAmount: 0.01, - maxTradeAmount: 10, - }, - { - symbol: 'USDT', - contractAddress: USDT_ADDRESS[chainId], - decimal: 6, - precision: 4, - minTradeAmount: 1, - maxTradeAmount: 1000, - }, - ] - const mockPairsFromMMUpdater = new Updater({ - name: 'mockPairsFromMMUpdater', - updater() { - return Promise.resolve({}) - }, - }) - mockPairsFromMMUpdater.cacheResult = ['USDT/ETH'] - updaterStack['tokenListFromImtokenUpdater'] = mockTokenListUpdate - updaterStack['pairsFromMMUpdater'] = mockPairsFromMMUpdater - updaterStack['markerMakerConfigUpdater'] = mockMarkerMakerConfigUpdater - updaterStack['tokenConfigsFromImtokenUpdater'] = mockTokenConfigsFromImtokenUpdater - }) - describe('dispatch to protocol signer', function () { - it('should create ammv1 order by uniswap v2', async function () { - const ammAddr = '0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852' - const signedOrderResp = await newOrder({ - signer: signer, - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1, - makerAddress: ammAddr, - quoteId: 'echo-testing-8888', - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'SELL', - amount: 0.1, - uniqId: 'testing-1111', - userAddr: Wallet.createRandom().address.toLowerCase(), - protocol: Protocol.AMMV1, - }, - }) - 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') - expect(order.makerAddress).eq('0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852') - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect(order.makerAssetData).eq( - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq('0x25657705a6be20511687d483f2fccfb2d92f6033') - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq('0x0000000000000000000000000000000000000000') - expect(order.takerAssetData).eq( - '0xf47261b00000000000000000000000000000000000000000000000000000000000000000' - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - // verify signature length, the signature is generated ramdonly. - expect(order.makerWalletSignature.length).eq(40) - // verify random values - expect(order.salt.length > 0).is.true - expect(Number(order.expirationTimeSeconds) > 0).is.true - }) - it('should create ammv2 order by uniswap v2', async function () { - const ammAddr = '0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852' - const payload = Buffer.from( - JSON.stringify({ - path: [WETH[chainId].toLowerCase(), USDT_ADDRESS[chainId].toLowerCase()], - }) - ).toString('base64') - const signedOrderResp = await newOrder({ - signer: signer, - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1, - makerAddress: ammAddr, - quoteId: 'echo-testing-8888', - payload: payload, - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'SELL', - amount: 0.1, - uniqId: 'testing-1111', - userAddr: Wallet.createRandom().address.toLowerCase(), - protocol: Protocol.AMMV2, - }, - }) - expect(signedOrderResp).is.not.null - // verify data object - const order = signedOrderResp.order - expect(order).is.not.null - expect(order.protocol).eq(Protocol.AMMV2) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq('0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852') - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect(order.makerAssetData).eq( - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq('0x25657705a6be20511687d483f2fccfb2d92f6033') - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq('0x0000000000000000000000000000000000000000') - expect(order.takerAssetData).eq( - '0xf47261b00000000000000000000000000000000000000000000000000000000000000000' - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - // verify signature length, the signature is generated ramdonly. - expect(order.makerWalletSignature.length).eq(40) - // verify random values - expect(order.salt.length > 0).is.true - expect(Number(order.expirationTimeSeconds) > 0).is.true - expect(order.payload).eq(payload) - }) - it('should raise error for pmmv4 order', async function () { - expect( - await newOrder({ - walletType: WalletType.MMP_VERSION_4, - signer: signer, - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1, - quoteId: 'echo-testing-9999', - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'SELL', - amount: 0.1, - uniqId: 'testing-1111', - userAddr: Wallet.createRandom().address.toLowerCase(), - protocol: 'PMMV4', - }, - }), - 'Unrecognized protocol: PMMV4' - ) - }) - it('should sign pmmv5 order for MMPv4', async function () { - const userAddr = Wallet.createRandom().address.toLowerCase() - const signedOrderResp = await newOrder({ - walletType: WalletType.MMP_VERSION_4, - signer: Wallet.createRandom(), - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1, - quoteId: 'echo-testing-8888', - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'SELL', - amount: 0.1, - uniqId: 'testing-1111', - userAddr: userAddr, - protocol: Protocol.PMMV5, - }, - }) - expect(signedOrderResp).is.not.null - // verify data object - const order = signedOrderResp.order - expect(order).is.not.null - expect(order.protocol).eq(Protocol.PMMV5) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq(signer.address.toLowerCase()) - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect(order.makerAssetData).eq( - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq('0x7bd7d025d4231aad1233967b527ffd7416410257') - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq(WETH[chainId].toLowerCase()) - expect(order.takerAssetData).eq( - `0xf47261b0000000000000000000000000${WETH[chainId].toLowerCase().slice(2)}` - ) - expect(order.senderAddress).eq('0x7bd7d025d4231aad1233967b527ffd7416410257') - expect(order.feeRecipientAddress).eq(userAddr) - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - // verify signature type - expect(signedOrderResp.order.makerWalletSignature.slice(-1)).eq('4') - // verify random values - expect(signedOrderResp.order.salt.length > 0).is.true - expect(Number(signedOrderResp.order.expirationTimeSeconds) > 0).is.true - }) - it('should sign pmmv5 order by EOA', async function () { - const userAddr = Wallet.createRandom().address.toLowerCase() - const signedOrderResp = await newOrder({ - walletType: WalletType.EOA, - signer: signer, - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1, - quoteId: 'echo-testing-8888', - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'SELL', - amount: 0.1, - uniqId: 'testing-1111', - userAddr: userAddr, - protocol: Protocol.PMMV5, - }, - }) - expect(signedOrderResp).is.not.null - // verify data object - const order = signedOrderResp.order - expect(order).is.not.null - expect(order.protocol).eq(Protocol.PMMV5) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq(signer.address.toLowerCase()) - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect(order.makerAssetData).eq( - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq('0x7bd7d025d4231aad1233967b527ffd7416410257') - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq(WETH[chainId].toLowerCase()) - expect(order.takerAssetData).eq( - `0xf47261b0000000000000000000000000${WETH[chainId].toLowerCase().slice(2)}` - ) - expect(order.senderAddress).eq('0x7bd7d025d4231aad1233967b527ffd7416410257') - expect(order.feeRecipientAddress).eq(userAddr) - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - // verify signature type - expect(signedOrderResp.order.makerWalletSignature.slice(-1)).eq('3') - // verify random values - expect(signedOrderResp.order.salt.length > 0).is.true - expect(Number(signedOrderResp.order.expirationTimeSeconds) > 0).is.true - }) - it('should sign rfqv2 order for MMPv4', async () => { - const ethersNetwork = await ethers.provider.getNetwork() - const chainId = ethersNetwork.chainId - const usdtHolder = await ethers.provider.getSigner(usdtHolders[chainId]) - const usdt = await ethers.getContractAt(ABI.IERC20, USDT[chainId]) - const [deployer, ethHolder] = await ethers.getSigners() - const privateKey = crypto.randomBytes(32) - const user = new ethers.Wallet(privateKey, ethers.provider) - const userAddr = user.address.toLowerCase() - await ethHolder.sendTransaction({ - to: userAddr, - value: ethers.utils.parseEther('10'), - }) - const mmpSigner = Wallet.createRandom() - console.log(`mmpSigner: ${mmpSigner.address}`) - const mmproxy: Contract = await ( - await ethers.getContractFactory('MarketMakerProxy', deployer) - ).deploy(mmpSigner.address) - await usdt.connect(usdtHolder).transfer(mmproxy.address, ethers.utils.parseUnits('1000', 6)) - // approve tokens to RFQV2 contract directly - await mmproxy.connect(deployer).setAllowance([USDT[chainId]], RFQV2[chainId]) - const mmproxyUsdtBalance = await usdt.balanceOf(mmproxy.address) - const mmproxyUsdtAllowance = await usdt.allowance(mmproxy.address, RFQV2[chainId]) - console.log(`mmproxyUsdtBalance: ${ethers.utils.formatUnits(mmproxyUsdtBalance, 6)}`) - console.log(`mmproxyUsdtAllowance: ${ethers.utils.formatUnits(mmproxyUsdtAllowance, 6)}`) - console.log(`mmproxy: ${mmproxy.address}`) - expect(mmproxy.address).is.not.null - replaceMarketMakingAddress(chainId, mmproxy.address, updaterStack) - const signedOrderResp = await newOrder({ - walletType: WalletType.MMP_VERSION_4, - signer: mmpSigner, - chainID: chainId, - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1, - quoteId: 'echo-testing-8888', - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'SELL', - amount: 0.1, - uniqId: 'testing-1111', - userAddr: userAddr, - protocol: Protocol.RFQV2, - }, - }) - expect(signedOrderResp).is.not.null - // verify data object - const order = signedOrderResp.order - console.log(order) - expect(order).is.not.null - expect(order.protocol).eq(Protocol.RFQV2) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq(mmproxy.address.toLowerCase()) - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect(order.makerAssetData).eq( - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq(userAddr) - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq(ZERO[chainId].toLowerCase()) - expect(order.takerAssetData).eq( - `0xf47261b0000000000000000000000000${ZERO[chainId].toLowerCase().slice(2)}` - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - // verify signature type - const sigBytes = utils.arrayify(signedOrderResp.order.makerWalletSignature) - expect(sigBytes.length).eq(88) - expect(sigBytes[87]).eq(SignatureType.Wallet) - // verify random values - expect(signedOrderResp.order.salt.length > 0).is.true - expect(Number(signedOrderResp.order.expirationTimeSeconds) > 0).is.true - const rfqAddr = RFQV2[chainId] - const orderSignDigest = getOfferSignDigest(toOffer(signedOrderResp.order), chainId, rfqAddr) - const message = ethUtils.bufferToHex( - Buffer.concat([ - ethUtils.toBuffer(orderSignDigest), - ethUtils.toBuffer(userAddr.toLowerCase()), - ethUtils.toBuffer(order.feeFactor > 255 ? order.feeFactor : [0, order.feeFactor]), - ]) - ) - const v = utils.hexlify(sigBytes.slice(0, 1)) - const r = utils.hexlify(sigBytes.slice(1, 33)) - const s = utils.hexlify(sigBytes.slice(33, 65)) - const recovered = utils.verifyMessage(utils.arrayify(message), { - v: parseInt(v), - r: r, - s: s, - }) - expect(recovered.toLowerCase()).eq(mmpSigner.address.toLowerCase()) - const result = await rfqv2.callStatic.isValidSignature( - mmproxy.address, - orderSignDigest, - '0x', - order.makerWalletSignature - ) - expect(result).true - }).timeout(360000) - it('should sign rfqv2 order for a ERC1271_EIP712_EIP191 MMP contract', async () => { - const usdtHolder = await ethers.provider.getSigner(usdtHolders[chainId]) - const usdt = await ethers.getContractAt(ABI.IERC20, USDT[chainId]) - const [deployer, ethHolder] = await ethers.getSigners() - const user = new ethers.Wallet(ethers.utils.randomBytes(32), ethers.provider) - const userAddr = user.address.toLowerCase() - await ethHolder.sendTransaction({ - to: userAddr, - value: ethers.utils.parseEther('10'), - }) - const mmpSigner = new ethers.Wallet(ethers.utils.randomBytes(32), ethers.provider) - console.log(`mmpSigner: ${mmpSigner.address}`) - await ethHolder.sendTransaction({ - to: mmpSigner.address, - value: ethers.utils.parseEther('10'), - }) - const mmproxy: Contract = await ( - await ethers.getContractFactory('EIP1271Plus191Wallet', deployer) - ).deploy(mmpSigner.address) - await usdt.connect(usdtHolder).transfer(mmproxy.address, ethers.utils.parseUnits('1000', 6)) - // approve tokens to RFQV2 contract directly - await mmproxy.connect(mmpSigner).setAllowance([USDT[chainId]], RFQV2[chainId]) - const mmproxyUsdtBalance = await usdt.balanceOf(mmproxy.address) - const mmproxyUsdtAllowance = await usdt.allowance(mmproxy.address, RFQV2[chainId]) - console.log(`mmproxyUsdtBalance: ${ethers.utils.formatUnits(mmproxyUsdtBalance, 6)}`) - console.log(`mmproxyUsdtAllowance: ${ethers.utils.formatUnits(mmproxyUsdtAllowance, 6)}`) - console.log(`mmproxy: ${mmproxy.address}`) - expect(mmproxy.address).is.not.null - replaceMarketMakingAddress(chainId, mmproxy.address, updaterStack) - const signedOrderResp = await newOrder({ - walletType: WalletType.ERC1271_EIP712_EIP191, - signer: mmpSigner, - chainID: chainId, - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1, - quoteId: 'echo-testing-8888', - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'SELL', - amount: 0.1, - uniqId: 'testing-1111', - userAddr: userAddr, - protocol: Protocol.RFQV2, - }, - }) - expect(signedOrderResp).is.not.null - // verify data object - const order = signedOrderResp.order - console.log(order) - expect(order).is.not.null - expect(order.protocol).eq(Protocol.RFQV2) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq(mmproxy.address.toLowerCase()) - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect(order.makerAssetData).eq( - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq(userAddr) - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq(ZERO[chainId].toLowerCase()) - expect(order.takerAssetData).eq( - `0xf47261b0000000000000000000000000${ZERO[chainId].toLowerCase().slice(2)}` - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - - // verify signature type - const sigBytes = utils.arrayify(signedOrderResp.order.makerWalletSignature) - expect(sigBytes.length).eq(66) - expect(sigBytes[65]).eq(SignatureType.WalletBytes32) - - // verify signature - const result = await rfqv2.callStatic.isValidSignature( - mmproxy.address, - getOfferSignDigest(toOffer(signedOrderResp.order), chainId, RFQV2[chainId]), - '0x', - order.makerWalletSignature - ) - expect(result).true - - // verify random values - expect(signedOrderResp.order.salt.length > 0).is.true - expect(Number(signedOrderResp.order.expirationTimeSeconds) > 0).is.true - }).timeout(360000) - it('should sign rfqv2 order for a ERC1271_EIP712 MMP contract', async () => { - const usdtHolder = await ethers.provider.getSigner(usdtHolders[chainId]) - const usdt = await ethers.getContractAt(ABI.IERC20, USDT[chainId]) - const [deployer, ethHolder] = await ethers.getSigners() - const privateKey = crypto.randomBytes(32) - const user = new ethers.Wallet(privateKey, ethers.provider) - const userAddr = user.address.toLowerCase() - await ethHolder.sendTransaction({ - to: userAddr, - value: ethers.utils.parseEther('10'), - }) - const mmpSigner = new ethers.Wallet(ethers.utils.randomBytes(32), ethers.provider) - console.log(`mmpSigner: ${mmpSigner.address}`) - await ethHolder.sendTransaction({ - to: mmpSigner.address, - value: ethers.utils.parseEther('10'), - }) - const mmproxy: Contract = await ( - await ethers.getContractFactory('EIP1271Wallet', deployer) - ).deploy(mmpSigner.address) - await usdt.connect(usdtHolder).transfer(mmproxy.address, ethers.utils.parseUnits('1000', 6)) - // approve tokens to RFQV2 contract directly - await mmproxy.connect(mmpSigner).setAllowance([USDT[chainId]], RFQV2[chainId]) - const mmproxyUsdtBalance = await usdt.balanceOf(mmproxy.address) - const mmproxyUsdtAllowance = await usdt.allowance(mmproxy.address, RFQV2[chainId]) - console.log(`mmproxyUsdtBalance: ${ethers.utils.formatUnits(mmproxyUsdtBalance, 6)}`) - console.log(`mmproxyUsdtAllowance: ${ethers.utils.formatUnits(mmproxyUsdtAllowance, 6)}`) - console.log(`mmproxy: ${mmproxy.address}`) - expect(mmproxy.address).is.not.null - replaceMarketMakingAddress(chainId, mmproxy.address, updaterStack) - const signedOrderResp = await newOrder({ - walletType: WalletType.ERC1271_EIP712, - signer: mmpSigner, - chainID: chainId, - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1, - quoteId: 'echo-testing-8888', - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'SELL', - amount: 0.1, - uniqId: 'testing-1111', - userAddr: userAddr, - protocol: Protocol.RFQV2, - }, - }) - expect(signedOrderResp).is.not.null - // verify data object - const order = signedOrderResp.order - console.log(order) - expect(order).is.not.null - expect(order.protocol).eq(Protocol.RFQV2) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq(mmproxy.address.toLowerCase()) - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect(order.makerAssetData).eq( - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq(userAddr) - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq(ZERO[chainId].toLowerCase()) - expect(order.takerAssetData).eq( - `0xf47261b0000000000000000000000000${ZERO[chainId].toLowerCase().slice(2)}` - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - - // verify signature type - const sigBytes = utils.arrayify(signedOrderResp.order.makerWalletSignature) - expect(sigBytes.length).eq(66) - expect(sigBytes[65]).eq(SignatureType.WalletBytes32) - - // verify signature - const result = await rfqv2.callStatic.isValidSignature( - mmproxy.address, - getOfferSignDigest(toOffer(signedOrderResp.order), chainId, RFQV2[chainId]), - '0x', - order.makerWalletSignature - ) - expect(result).true - - // verify random values - expect(signedOrderResp.order.salt.length > 0).is.true - expect(Number(signedOrderResp.order.expirationTimeSeconds) > 0).is.true - }).timeout(360000) - it('should sign rfqv2 order by EIP712', async function () { - replaceMarketMakingAddress(chainId, signer.address, updaterStack) - const userAddr = Wallet.createRandom().address.toLowerCase() - const usdt = new ethers.Contract(USDT[chainId], ABI.IERC20, ethers.provider) - await usdt.connect(signer).approve(RFQV2[chainId], ethers.constants.MaxUint256) - const signedOrderResp = await newOrder({ - walletType: WalletType.EOA, - signer: signer, - chainID: chainId, - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1, - quoteId: 'echo-testing-8888', - }) - }, - }, - query: { - base: 'USDT', - quote: 'ETH', - side: 'SELL', - amount: 1, - uniqId: 'testing-1111', - userAddr: userAddr, - protocol: Protocol.RFQV2, - }, - }) - expect(signedOrderResp).is.not.null - // verify data object - const order = signedOrderResp.order - console.log(order) - expect(order).is.not.null - expect(order.protocol).eq(Protocol.RFQV2) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq(signer.address.toLowerCase()) - expect(order.makerAssetAmount).eq('1000000000000000000') - expect(order.makerAssetAddress).eq(WETH[chainId].toLowerCase()) - expect( - order.makerAssetData, - `0xf47261b0000000000000000000000000${WETH[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq(userAddr) - expect(order.takerAssetAmount).eq('1000000') - expect(order.takerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect( - order.takerAssetData, - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - // verify signature type - const sigBytes = utils.arrayify(signedOrderResp.order.makerWalletSignature) - expect(sigBytes.length).eq(66) - expect(sigBytes[65]).eq(SignatureType.EIP712) - // verify signature - const result = await rfqv2.callStatic.isValidSignature( - signer.address, - getOfferSignDigest(toOffer(signedOrderResp.order), chainId, RFQV2[chainId]), - '0x', - order.makerWalletSignature - ) - expect(result).true - - // verify random values - expect(signedOrderResp.order.salt.length > 0).is.true - expect(Number(signedOrderResp.order.expirationTimeSeconds) > 0).is.true - }) - it('should sign rfqv1 order for MMPv4', async () => { - const ethersNetwork = await ethers.provider.getNetwork() - const chainId = ethersNetwork.chainId - const usdtHolder = await ethers.provider.getSigner(usdtHolders[chainId]) - const usdt = await ethers.getContractAt(ABI.IERC20, USDT[chainId]) - const [deployer, ethHolder] = await ethers.getSigners() - const privateKey = crypto.randomBytes(32) - const user = new ethers.Wallet(privateKey, ethers.provider) - const userAddr = user.address.toLowerCase() - await ethHolder.sendTransaction({ - to: userAddr, - value: ethers.utils.parseEther('10'), - }) - const mmpSigner = Wallet.createRandom() - console.log(`mmpSigner: ${mmpSigner.address}`) - const mmproxy: Contract = await ( - await ethers.getContractFactory('MarketMakerProxy', deployer) - ).deploy(mmpSigner.address) - await usdt.connect(usdtHolder).transfer(mmproxy.address, ethers.utils.parseUnits('1000', 6)) - await mmproxy.connect(deployer).setAllowance([USDT[chainId]], AllowanceTarget[chainId]) - const mmproxyUsdtBalance = await usdt.balanceOf(mmproxy.address) - const mmproxyUsdtAllowance = await usdt.allowance(mmproxy.address, AllowanceTarget[chainId]) - console.log(`mmproxyUsdtBalance: ${ethers.utils.formatUnits(mmproxyUsdtBalance, 6)}`) - console.log(`mmproxyUsdtAllowance: ${ethers.utils.formatUnits(mmproxyUsdtAllowance, 6)}`) - console.log(`mmproxy: ${mmproxy.address}`) - expect(mmproxy.address).is.not.null - replaceMarketMakingAddress(chainId, mmproxy.address, updaterStack) - const signedOrderResp = await newOrder({ - walletType: WalletType.MMP_VERSION_4, - signer: mmpSigner, - chainID: chainId, - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1, - quoteId: 'echo-testing-8888', - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'SELL', - amount: 0.1, - uniqId: 'testing-1111', - userAddr: userAddr, - protocol: Protocol.RFQV1, - }, - }) - expect(signedOrderResp).is.not.null - // verify data object - const order = signedOrderResp.order - console.log(order) - expect(order).is.not.null - expect(order.protocol).eq(Protocol.RFQV1) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq(mmproxy.address.toLowerCase()) - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect(order.makerAssetData).eq( - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq(userAddr) - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq(WETH[chainId].toLowerCase()) - expect(order.takerAssetData).eq( - `0xf47261b0000000000000000000000000${WETH[chainId].toLowerCase().slice(2)}` - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - // verify signature type - const sigBytes = utils.arrayify(signedOrderResp.order.makerWalletSignature) - expect(sigBytes.length).eq(88) - expect(sigBytes[87]).eq(SignatureType.Wallet) - // verify random values - expect(signedOrderResp.order.salt.length > 0).is.true - expect(Number(signedOrderResp.order.expirationTimeSeconds) > 0).is.true - const rfqAddr = RFQV1[chainId] - const orderSignDigest = getOrderSignDigest( - toRFQOrder(signedOrderResp.order), - chainId, - rfqAddr - ) - const message = ethUtils.bufferToHex( - Buffer.concat([ - ethUtils.toBuffer(orderSignDigest), - ethUtils.toBuffer(userAddr.toLowerCase()), - ethUtils.toBuffer(order.feeFactor > 255 ? order.feeFactor : [0, order.feeFactor]), - ]) - ) - const v = utils.hexlify(sigBytes.slice(0, 1)) - const r = utils.hexlify(sigBytes.slice(1, 33)) - const s = utils.hexlify(sigBytes.slice(33, 65)) - const recovered = utils.verifyMessage(utils.arrayify(message), { - v: parseInt(v), - r: r, - s: s, - }) - console.log(`recovered: ${recovered}`) - console.log(`mmpSigner.address: ${mmpSigner.address}`) - expect(recovered.toLowerCase()).eq(mmpSigner.address.toLowerCase()) - const result = await rfqv1.callStatic.isValidSignature( - mmproxy.address, - orderSignDigest, - '0x', - order.makerWalletSignature - ) - console.log(`result: ${result}`) - expect(result).true - }).timeout(360000) - it('should sign rfqv1 order for a ERC1271_EIP712_EIP191 MMP contract', async () => { - const ethersNetwork = await ethers.provider.getNetwork() - const chainId = ethersNetwork.chainId - const usdtHolder = await ethers.provider.getSigner(usdtHolders[chainId]) - const usdt = await ethers.getContractAt(ABI.IERC20, USDT[chainId]) - const [deployer, ethHolder] = await ethers.getSigners() - const privateKey = crypto.randomBytes(32) - const user = new ethers.Wallet(privateKey, ethers.provider) - const userAddr = user.address.toLowerCase() - await ethHolder.sendTransaction({ - to: userAddr, - value: ethers.utils.parseEther('10'), - }) - const mmpSigner = Wallet.createRandom() - console.log(`mmpSigner: ${mmpSigner.address}`) - const mmproxy: Contract = await ( - await ethers.getContractFactory('MarketMakerProxy', deployer) - ).deploy(mmpSigner.address) - await usdt.connect(usdtHolder).transfer(mmproxy.address, ethers.utils.parseUnits('1000', 6)) - await mmproxy.connect(deployer).setAllowance([USDT[chainId]], AllowanceTarget[chainId]) - const mmproxyUsdtBalance = await usdt.balanceOf(mmproxy.address) - const mmproxyUsdtAllowance = await usdt.allowance(mmproxy.address, AllowanceTarget[chainId]) - console.log(`mmproxyUsdtBalance: ${ethers.utils.formatUnits(mmproxyUsdtBalance, 6)}`) - console.log(`mmproxyUsdtAllowance: ${ethers.utils.formatUnits(mmproxyUsdtAllowance, 6)}`) - console.log(`mmproxy: ${mmproxy.address}`) - expect(mmproxy.address).is.not.null - replaceMarketMakingAddress(chainId, mmproxy.address, updaterStack) - const signedOrderResp = await newOrder({ - walletType: WalletType.ERC1271_EIP712_EIP191, - signer: mmpSigner, - chainID: chainId, - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1, - quoteId: 'echo-testing-8888', - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'SELL', - amount: 0.1, - uniqId: 'testing-1111', - userAddr: userAddr, - protocol: Protocol.RFQV1, - }, - }) - expect(signedOrderResp).is.not.null - // verify data object - const order = signedOrderResp.order - console.log(order) - expect(order).is.not.null - expect(order.protocol).eq(Protocol.RFQV1) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq(mmproxy.address.toLowerCase()) - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect(order.makerAssetData).eq( - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq(userAddr) - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq(WETH[chainId].toLowerCase()) - expect(order.takerAssetData).eq( - `0xf47261b0000000000000000000000000${WETH[chainId].toLowerCase().slice(2)}` - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - // verify signature type - const sigBytes = utils.arrayify(signedOrderResp.order.makerWalletSignature) - expect(sigBytes.length).eq(66) - expect(sigBytes[65]).eq(SignatureType.WalletBytes32) - // verify random values - expect(signedOrderResp.order.salt.length > 0).is.true - expect(Number(signedOrderResp.order.expirationTimeSeconds) > 0).is.true - const orderSignDigest = getOrderSignDigest( - toRFQOrder(signedOrderResp.order), - chainId, - RFQV1[chainId] - ) - const r = utils.hexlify(sigBytes.slice(0, 32)) - const s = utils.hexlify(sigBytes.slice(32, 64)) - const v = utils.hexlify(sigBytes.slice(64, 65)) - console.log(`r: ${r}`) - console.log(`s: ${s}`) - console.log(`v: ${v}`) - const recovered = utils.verifyMessage(utils.arrayify(orderSignDigest), { - v: parseInt(v), - r: r, - s: s, - }) - expect(recovered.toLowerCase()).eq(mmpSigner.address.toLowerCase()) - console.log(`recovered.toLowerCase(): ${recovered.toLowerCase()}`) - console.log(`mmpSigner.address.toLowerCase(): ${mmpSigner.address.toLowerCase()}`) - // TODO: call isValidSignature with a real ERC1271 wallet contract - }).timeout(360000) - it('should sign rfqv1 order for a ERC1271_EIP712 MMP contract', async () => { - const ethersNetwork = await ethers.provider.getNetwork() - const chainId = ethersNetwork.chainId - const usdtHolder = await ethers.provider.getSigner(usdtHolders[chainId]) - const usdt = await ethers.getContractAt(ABI.IERC20, USDT[chainId]) - const [deployer, ethHolder] = await ethers.getSigners() - const privateKey = crypto.randomBytes(32) - const user = new ethers.Wallet(privateKey, ethers.provider) - const userAddr = user.address.toLowerCase() - await ethHolder.sendTransaction({ - to: userAddr, - value: ethers.utils.parseEther('10'), - }) - const mmpSigner = Wallet.createRandom() - console.log(`mmpSigner: ${mmpSigner.address}`) - const mmproxy: Contract = await ( - await ethers.getContractFactory('MarketMakerProxy', deployer) - ).deploy(mmpSigner.address) - await usdt.connect(usdtHolder).transfer(mmproxy.address, ethers.utils.parseUnits('1000', 6)) - await mmproxy.connect(deployer).setAllowance([USDT[chainId]], AllowanceTarget[chainId]) - const mmproxyUsdtBalance = await usdt.balanceOf(mmproxy.address) - const mmproxyUsdtAllowance = await usdt.allowance(mmproxy.address, AllowanceTarget[chainId]) - console.log(`mmproxyUsdtBalance: ${ethers.utils.formatUnits(mmproxyUsdtBalance, 6)}`) - console.log(`mmproxyUsdtAllowance: ${ethers.utils.formatUnits(mmproxyUsdtAllowance, 6)}`) - console.log(`mmproxy: ${mmproxy.address}`) - expect(mmproxy.address).is.not.null - replaceMarketMakingAddress(chainId, mmproxy.address, updaterStack) - const signedOrderResp = await newOrder({ - walletType: WalletType.ERC1271_EIP712, - signer: mmpSigner, - chainID: chainId, - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1, - quoteId: 'echo-testing-8888', - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'SELL', - amount: 0.1, - uniqId: 'testing-1111', - userAddr: userAddr, - protocol: Protocol.RFQV1, - }, - }) - expect(signedOrderResp).is.not.null - // verify data object - const order = signedOrderResp.order - console.log(order) - expect(order).is.not.null - expect(order.protocol).eq(Protocol.RFQV1) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq(mmproxy.address.toLowerCase()) - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect(order.makerAssetData).eq( - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq(userAddr) - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq(WETH[chainId].toLowerCase()) - expect(order.takerAssetData).eq( - `0xf47261b0000000000000000000000000${WETH[chainId].toLowerCase().slice(2)}` - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - // verify signature type - const sigBytes = utils.arrayify(signedOrderResp.order.makerWalletSignature) - expect(sigBytes.length).eq(66) - expect(sigBytes[65]).eq(SignatureType.WalletBytes32) - // verify random values - expect(signedOrderResp.order.salt.length > 0).is.true - expect(Number(signedOrderResp.order.expirationTimeSeconds) > 0).is.true - const r = utils.hexlify(sigBytes.slice(0, 32)) - const s = utils.hexlify(sigBytes.slice(32, 64)) - const v = utils.hexlify(sigBytes.slice(64, 65)) - console.log(`r: ${r}`) - console.log(`s: ${s}`) - console.log(`v: ${v}`) - const rfqOrder = toRFQOrder(signedOrderResp.order) - const domain = { - name: 'Tokenlon', - version: 'v5', - chainId: chainId, - verifyingContract: RFQV1[chainId], - } - const types = { - Order: [ - { name: 'takerAddr', type: 'address' }, - { name: 'makerAddr', type: 'address' }, - { name: 'takerAssetAddr', type: 'address' }, - { name: 'makerAssetAddr', type: 'address' }, - { name: 'takerAssetAmount', type: 'uint256' }, - { name: 'makerAssetAmount', type: 'uint256' }, - { name: 'salt', type: 'uint256' }, - { name: 'deadline', type: 'uint256' }, - { name: 'feeFactor', type: 'uint256' }, - ], - } - const value = { - takerAddr: rfqOrder.takerAddr, - makerAddr: rfqOrder.makerAddr, - takerAssetAddr: rfqOrder.takerAssetAddr, - makerAssetAddr: rfqOrder.makerAssetAddr, - takerAssetAmount: rfqOrder.takerAssetAmount.toString(), - makerAssetAmount: rfqOrder.makerAssetAmount.toString(), - salt: rfqOrder.salt.toString(), - deadline: rfqOrder.deadline.toString(), - feeFactor: rfqOrder.feeFactor.toString(), - } - const recovered = ethers.utils.verifyTypedData( - domain, - types, - value, - order.makerWalletSignature.slice(0, -2) - ) - expect(recovered.toLowerCase()).eq(mmpSigner.address.toLowerCase()) - console.log(`recovered.toLowerCase(): ${recovered.toLowerCase()}`) - console.log(`mmpSigner.address.toLowerCase(): ${mmpSigner.address.toLowerCase()}`) - // TODO: call isValidSignature with a real ERC1271 wallet contract - }).timeout(360000) - it('should sign rfqv1 order by EIP712', async function () { - replaceMarketMakingAddress(chainId, signer.address, updaterStack) - const userAddr = Wallet.createRandom().address.toLowerCase() - const signedOrderResp = await newOrder({ - walletType: WalletType.EOA, - signer: signer, - chainID: chainId, - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1, - quoteId: 'echo-testing-8888', - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'SELL', - amount: 0.1, - uniqId: 'testing-1111', - userAddr: userAddr, - protocol: Protocol.RFQV1, - }, - }) - expect(signedOrderResp).is.not.null - // verify data object - const order = signedOrderResp.order - console.log(order) - expect(order).is.not.null - expect(order.protocol).eq(Protocol.RFQV1) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq(signer.address.toLowerCase()) - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect( - order.makerAssetData, - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq(userAddr) - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq(WETH[chainId].toLowerCase()) - expect( - order.takerAssetData, - `0xf47261b0000000000000000000000000${WETH[chainId].toLowerCase().slice(2)}` - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - // verify signature type - const sigBytes = utils.arrayify(signedOrderResp.order.makerWalletSignature) - expect(sigBytes.length).eq(98) - expect(sigBytes[97]).eq(SignatureType.EIP712) - // verify signature - const orderSignDigest = getOrderSignDigest( - toRFQOrder(signedOrderResp.order), - chainId, - RFQV1[chainId] - ) - const result = await rfqv1.callStatic.isValidSignature( - signer.address, - orderSignDigest, - '0x', - order.makerWalletSignature - ) - console.log(`result: ${result}`) - expect(result).true - // verify random values - expect(signedOrderResp.order.salt.length > 0).is.true - expect(Number(signedOrderResp.order.expirationTimeSeconds) > 0).is.true - }) - }) - describe('handle token precision and decimals', () => { - it('should format taker asset amount', async function () { - const signedOrderResp = await newOrder({ - walletType: WalletType.MMP_VERSION_4, - signer: Wallet.createRandom(), - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1.1, - quoteId: 'echo-testing-8888', - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'BUY', - amount: 0.1111, - feeFactor: 10, - uniqId: 'testing-1111', - userAddr: Wallet.createRandom().address.toLowerCase(), - protocol: Protocol.PMMV5, - }, - }) - expect(signedOrderResp).is.not.null - expect(signedOrderResp.order.quoteId).eq('1--echo-testing-8888') - expect(signedOrderResp.order.makerWalletSignature.slice(-1)).eq('4') - expect(signedOrderResp.order.takerAssetData.slice(34)).eq( - USDT_ADDRESS[chainId].toLowerCase().slice(2) - ) - expect(signedOrderResp.order.takerAssetAmount).eq(utils.parseUnits('0.122539', 6).toString()) - expect(signedOrderResp.order.makerAssetAmount).eq(utils.parseEther('0.1114').toString()) - }) - it('should format maker asset amount', async function () { - const signedOrderResp = await newOrder({ - walletType: WalletType.MMP_VERSION_4, - signer: Wallet.createRandom(), - quoter: { - getPrice: () => { - return Promise.resolve({ - result: true, - exchangeable: true, - minAmount: 0, - maxAmount: 1000, - price: 1.1, - quoteId: 'echo-testing-8888', - }) - }, - }, - query: { - base: 'ETH', - quote: 'USDT', - side: 'SELL', - amount: 0.1111, - uniqId: 'testing-1111', - userAddr: Wallet.createRandom().address.toLowerCase(), - protocol: Protocol.PMMV5, - }, - }) - expect(signedOrderResp).is.not.null - expect(signedOrderResp.order.quoteId).eq('1--echo-testing-8888') - expect(signedOrderResp.order.makerWalletSignature.slice(-1)).eq('4') - expect(signedOrderResp.order.takerAssetAmount).eq(utils.parseEther('0.1111').toString()) - expect(signedOrderResp.order.makerAssetAmount).eq(utils.parseUnits('0.12221', 6).toString()) - }) - }) - it('Should forward unsigned PMMV5 orders to signing service', async () => { - const url = `http://localhost:3000` - const pmm = '0x8D90113A1e286a5aB3e496fbD1853F265e5913c6' - const order: ExtendedZXOrder = { - protocol: Protocol.PMMV5, - quoteId: `0x123`, - exchangeAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`.toLowerCase(), - feeRecipientAddress: `0x45352`, - senderAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`, - takerAddress: '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', - makerAddress: '0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64'.toLowerCase(), - takerAssetData: assetDataUtils.encodeERC20AssetData(WETH[chainId]), - makerAssetData: assetDataUtils.encodeERC20AssetData(USDT_ADDRESS[chainId]), - takerFee: toBN(0), - makerFee: toBN(0), - takerAssetAddress: WETH[chainId], - makerAssetAddress: USDT_ADDRESS[chainId], - 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 = RFQV1[chainId] - const order: ExtendedZXOrder = { - protocol: Protocol.RFQV1, - quoteId: `0x123`, - exchangeAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`.toLowerCase(), - feeRecipientAddress: `0x45352`, - senderAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`, - takerAddress: '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', - makerAddress: '0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64'.toLowerCase(), - takerAssetData: assetDataUtils.encodeERC20AssetData(WETH[chainId]), - makerAssetData: assetDataUtils.encodeERC20AssetData(USDT_ADDRESS[chainId]), - takerFee: toBN(0), - makerFee: toBN(0), - takerAssetAddress: WETH[chainId], - makerAssetAddress: USDT_ADDRESS[chainId], - 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 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 = RFQV2[chainId] - const order: ExtendedZXOrder = { - protocol: Protocol.RFQV2, - quoteId: `0x123`, - exchangeAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`.toLowerCase(), - feeRecipientAddress: `0x45352`, - senderAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`, - takerAddress: '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', - makerAddress: '0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64'.toLowerCase(), - takerAssetData: assetDataUtils.encodeERC20AssetData(WETH[chainId]), - makerAssetData: assetDataUtils.encodeERC20AssetData(USDT_ADDRESS[chainId]), - takerFee: toBN(0), - makerFee: toBN(0), - takerAssetAddress: WETH[chainId], - makerAssetAddress: USDT_ADDRESS[chainId], - 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(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/pmm.spec.ts b/test/pmm.spec.ts new file mode 100644 index 0000000..5ffe8f8 --- /dev/null +++ b/test/pmm.spec.ts @@ -0,0 +1,191 @@ +import { ethers, network } from 'hardhat' +import { Wallet, utils } from 'ethers' +import { updaterStack } from '../src/worker' +import { Protocol } from '../src/types' +import { EIP712_ORDER_SCHEMA, buildSignedOrder as buildPMMV5SignedOrder } from '../src/signer/pmmv5' +import { ExtendedZXOrder, WalletType } from '../src/signer/types' +import { BigNumber, toBN } from '../src/utils' +import { ABI, WETH } from '@tokenlon/sdk' +import { expect } from 'chai' +import { assetDataUtils, eip712Utils, orderHashUtils } from '0x-v2-order-utils' +import * as nock from 'nock' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { + USDT_ADDRESS, + WALLET_TYPE_MAGIC_VALUE, + callNewOrder, + deployMMPV4Wallet, + init, + replaceMarketMakingAddress, + toZXOrder, + usdtHolders, +} from './utils' + +describe('PMM NewOrder', function () { + const chainId: number = network.config.chainId! + let signer: SignerWithAddress + before(async () => { + const signers = await ethers.getSigners() + signer = signers[0] + const usdtHolderAddr = usdtHolders[chainId] + await network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [usdtHolderAddr], + }) + }) + beforeEach(() => { + init(chainId, signer) + }) + it('should raise error for pmmv4 order', async function () { + expect( + await callNewOrder({ + chainId: chainId, + base: 'ETH', + quote: 'USDT', + side: 'SELL', + amount: 0.1, + signer, + walletType: WalletType.MMP_VERSION_4, + userAddr: Wallet.createRandom().address.toLowerCase(), + protocol: 'PMMV4', + }), + 'Unrecognized protocol: PMMV4' + ) + }) + it('should sign pmmv5 order by EOA', async function () { + replaceMarketMakingAddress(chainId, signer.address, updaterStack) + const userAddr = Wallet.createRandom().address.toLowerCase() + const order = await callNewOrder({ + chainId: chainId, + base: 'ETH', + quote: 'USDT', + side: 'SELL', + amount: 0.1, + userAddr: userAddr, + protocol: Protocol.PMMV5, + signer, + walletType: WalletType.EOA, + }) + expect(order).is.not.null + expect(order.protocol).eq(Protocol.PMMV5) + expect(order.quoteId).eq('1--echo-testing-8888') + expect(order.makerAddress).eq(signer.address.toLowerCase()) + expect(order.makerAssetAmount).eq('100000') + expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) + expect(order.makerAssetData).eq( + `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` + ) + expect(order.takerAddress).eq('0x7bd7d025d4231aad1233967b527ffd7416410257') + expect(order.takerAssetAmount).eq('100000000000000000') + expect(order.takerAssetAddress).eq(WETH[chainId].toLowerCase()) + expect(order.takerAssetData).eq( + `0xf47261b0000000000000000000000000${WETH[chainId].toLowerCase().slice(2)}` + ) + expect(order.senderAddress).eq('0x7bd7d025d4231aad1233967b527ffd7416410257') + expect(order.feeRecipientAddress).eq(userAddr) + expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') + // The following fields are to be compatible `Order` struct. + expect(order.makerFee).eq('0') + expect(order.takerFee).eq('0') + // verify signature type + expect(order.makerWalletSignature?.slice(-1)).eq('3') + // verify random values + expect(order.salt?.toString().length).gt(0) + expect(Number(order.expirationTimeSeconds)).gt(0) + const zxOrder = toZXOrder(order) + const orderHashBuffer = eip712Utils.structHash(EIP712_ORDER_SCHEMA, zxOrder) + const orderHash = '0x' + orderHashBuffer.toString('hex') + console.log(`orderHash: ${orderHash}`) + const orderSignDigest = orderHashUtils.getOrderHashHex(zxOrder) + console.log(`orderSignDigest: ${orderSignDigest}`) + const sigBytes = utils.arrayify(order.makerWalletSignature!) + const v = utils.hexlify(sigBytes.slice(0, 1)) + const r = utils.hexlify(sigBytes.slice(1, 33)) + const s = utils.hexlify(sigBytes.slice(33, 65)) + const recovered = ethers.utils.verifyMessage(utils.arrayify(orderSignDigest), { + v: parseInt(v), + r: r, + s: s, + }) + expect(recovered.toLowerCase()).eq(signer.address.toLowerCase()) + }) + it('should sign pmmv5 order for MMPv4', async function () { + const usdtHolder = await ethers.provider.getSigner(usdtHolders[chainId]) + const usdt = await ethers.getContractAt(ABI.IERC20, USDT_ADDRESS[chainId]) + const mmpSigner = Wallet.createRandom() + const [deployer] = await ethers.getSigners() + const mmproxy = await deployMMPV4Wallet(mmpSigner, deployer) + replaceMarketMakingAddress(chainId, mmproxy.address, updaterStack) + await usdt.connect(usdtHolder).transfer(mmproxy.address, ethers.utils.parseUnits('1000', 6)) + const userAddr = Wallet.createRandom().address.toLowerCase() + const order = await callNewOrder({ + chainId: chainId, + base: 'ETH', + quote: 'USDT', + side: 'SELL', + amount: 0.1, + userAddr: userAddr, + protocol: Protocol.PMMV5, + signer: mmpSigner, + makerAddress: mmproxy.address, + walletType: WalletType.MMP_VERSION_4, + }) + console.log(`order.makerWalletSignature: ${order.makerWalletSignature}`) + const magicValue = await mmproxy.callStatic.isValidSignature( + orderHashUtils.getOrderHashHex(toZXOrder(order)), + order.makerWalletSignature?.slice(0, -2) + ) + console.log(`magicValue: ${magicValue}`) + expect(magicValue).eq(WALLET_TYPE_MAGIC_VALUE) + }) + it('Should forward unsigned PMMV5 orders to signing service', async () => { + const url = `http://localhost:3000` + const pmm = '0x8D90113A1e286a5aB3e496fbD1853F265e5913c6' + const order: ExtendedZXOrder = { + protocol: Protocol.PMMV5, + quoteId: `0x123`, + exchangeAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`.toLowerCase(), + feeRecipientAddress: `0x45352`, + senderAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`, + takerAddress: '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', + makerAddress: '0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64'.toLowerCase(), + takerAssetData: assetDataUtils.encodeERC20AssetData(WETH[chainId]), + makerAssetData: assetDataUtils.encodeERC20AssetData(USDT_ADDRESS[chainId]), + takerFee: toBN(0), + makerFee: toBN(0), + takerAssetAddress: WETH[chainId], + makerAssetAddress: USDT_ADDRESS[chainId], + 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) + }) +}) diff --git a/test/rfqv1.spec.ts b/test/rfqv1.spec.ts new file mode 100644 index 0000000..566385a --- /dev/null +++ b/test/rfqv1.spec.ts @@ -0,0 +1,270 @@ +import { ethers, network } from 'hardhat' +import { Wallet, utils, Contract } from 'ethers' +import { updaterStack } from '../src/worker' +import { Protocol } from '../src/types' +import { toRFQOrder } from '../src/signer/rfqv1' +import { buildSignedOrder as buildRFQV1SignedOrder } from '../src/signer/rfqv1' +import { ExtendedZXOrder, SignatureType, WalletType } from '../src/signer/types' +import { getOrderSignDigest } from '../src/signer/orderHash' +import { BigNumber, toBN } from '../src/utils' +import { WETH } from '@tokenlon/sdk' +import * as crypto from 'crypto' +import { expect } from 'chai' +import { assetDataUtils } from '0x-v2-order-utils' +import * as nock from 'nock' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { + RFQV1, + USDT_ADDRESS, + callNewOrder, + deployEIP1271Plus191Wallet, + deployERC1271Wallet, + deployMMPV4Wallet, + init, + replaceMarketMakingAddress, + usdtHolders, +} from './utils' + +describe('RFQV1 NewOrder', function () { + const chainId: number = network.config.chainId! + let signer: SignerWithAddress + let rfqv1: Contract + before(async () => { + const signers = await ethers.getSigners() + signer = signers[0] + const usdtHolderAddr = usdtHolders[chainId] + rfqv1 = await ethers.getContractAt('ISignatureValidator', RFQV1[chainId]) + await network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [usdtHolderAddr], + }) + }) + beforeEach(() => { + init(chainId, signer) + }) + it('should sign rfqv1 order by EIP712', async function () { + replaceMarketMakingAddress(chainId, signer.address, updaterStack) + const userAddr = Wallet.createRandom().address.toLowerCase() + const order = await callNewOrder({ + chainId: chainId, + base: 'ETH', + quote: 'USDT', + side: 'SELL', + amount: 0.1, + userAddr: userAddr, + walletType: WalletType.EOA, + signer: signer, + protocol: Protocol.RFQV1, + }) + console.log(order) + expect(order).is.not.null + expect(order.protocol).eq(Protocol.RFQV1) + expect(order.quoteId).eq('1--echo-testing-8888') + expect(order.makerAddress).eq(signer.address.toLowerCase()) + expect(order.makerAssetAmount).eq('100000') + expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) + expect( + order.makerAssetData, + `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` + ) + expect(order.takerAddress).eq(userAddr) + expect(order.takerAssetAmount).eq('100000000000000000') + expect(order.takerAssetAddress).eq(WETH[chainId].toLowerCase()) + expect( + order.takerAssetData, + `0xf47261b0000000000000000000000000${WETH[chainId].toLowerCase().slice(2)}` + ) + expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') + expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') + expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') + // The following fields are to be compatible `Order` struct. + expect(order.makerFee).eq('0') + expect(order.takerFee).eq('0') + // verify signature type + const sigBytes = utils.arrayify(order.makerWalletSignature!) + expect(sigBytes.length).eq(98) + expect(sigBytes[97]).eq(SignatureType.EIP712) + // verify signature + const orderSignDigest = getOrderSignDigest(toRFQOrder(order), chainId, RFQV1[chainId]) + const isValid = await rfqv1.callStatic.isValidSignature( + signer.address, + orderSignDigest, + '0x', + order.makerWalletSignature + ) + expect(isValid).true + // verify random values + expect(order.salt?.toString().length).gt(0) + expect(Number(order.expirationTimeSeconds)).gt(0) + }) + it('should sign rfqv1 order for MMPv4', async () => { + const user = Wallet.createRandom() + const userAddr = user.address.toLowerCase() + const [deployer] = await ethers.getSigners() + const mmpSigner = Wallet.createRandom() + console.log(`mmpSigner: ${mmpSigner.address}`) + const mmproxy = await deployMMPV4Wallet(mmpSigner, deployer) + console.log(`mmproxy: ${mmproxy.address}`) + expect(mmproxy.address).is.not.null + replaceMarketMakingAddress(chainId, mmproxy.address, updaterStack) + const order = await callNewOrder({ + base: 'ETH', + quote: 'USDT', + side: 'SELL', + amount: 0.1, + userAddr: userAddr, + walletType: WalletType.MMP_VERSION_4, + signer: mmpSigner, + chainId: chainId, + protocol: Protocol.RFQV1, + }) + // verify signature type + const sigBytes = utils.arrayify(order.makerWalletSignature!) + expect(sigBytes.length).eq(88) + expect(sigBytes[87]).eq(SignatureType.Wallet) + // verify random values + expect(order.salt?.toString().length).gt(0) + expect(Number(order.expirationTimeSeconds) > 0).is.true + const orderSignDigest = getOrderSignDigest(toRFQOrder(order), chainId, RFQV1[chainId]) + const isValid = await rfqv1.callStatic.isValidSignature( + order.makerAddress, + orderSignDigest, + '0x', + order.makerWalletSignature + ) + console.log(`isValid: ${isValid}`) + expect(isValid).true + }).timeout(360000) + it('should sign rfqv1 order for a ERC1271_EIP712_EIP191 MMP contract', async () => { + const [deployer] = await ethers.getSigners() + const privateKey = crypto.randomBytes(32) + const user = new ethers.Wallet(privateKey, ethers.provider) + const userAddr = user.address.toLowerCase() + const allowSigner = Wallet.createRandom() + console.log(`allowSigner: ${allowSigner.address}`) + const walletContract = await deployEIP1271Plus191Wallet(allowSigner, deployer) + expect(walletContract.address).is.not.null + replaceMarketMakingAddress(chainId, walletContract.address, updaterStack) + const order = await callNewOrder({ + base: 'ETH', + quote: 'USDT', + side: 'SELL', + amount: 0.1, + userAddr: userAddr, + chainId: chainId, + walletType: WalletType.ERC1271_EIP712_EIP191, + signer: allowSigner, + protocol: Protocol.RFQV1, + }) + // verify signature type + const sigBytes = utils.arrayify(order.makerWalletSignature!) + expect(sigBytes.length).eq(66) + expect(sigBytes[65]).eq(SignatureType.WalletBytes32) + // verify random values + expect(order.salt?.toString().length).gt(0) + expect(Number(order.expirationTimeSeconds)).gt(0) + const orderSignDigest = getOrderSignDigest(toRFQOrder(order), chainId, RFQV1[chainId]) + const isValid = await rfqv1.callStatic.isValidSignature( + order.makerAddress, + orderSignDigest, + '0x', + order.makerWalletSignature + ) + console.log(`isValid: ${isValid}`) + expect(isValid).true + }).timeout(360000) + it('should sign rfqv1 order for a ERC1271_EIP712 MMP contract', async () => { + const [deployer] = await ethers.getSigners() + const user = Wallet.createRandom() + const userAddr = user.address.toLowerCase() + const allowSigner = Wallet.createRandom() + console.log(`allowSigner: ${allowSigner.address}`) + const walletContract = await deployERC1271Wallet(allowSigner, deployer) + expect(walletContract.address).is.not.null + replaceMarketMakingAddress(chainId, walletContract.address, updaterStack) + const order = await callNewOrder({ + base: 'ETH', + quote: 'USDT', + side: 'SELL', + amount: 0.1, + walletType: WalletType.ERC1271_EIP712, + signer: allowSigner, + chainId: chainId, + userAddr: userAddr, + protocol: Protocol.RFQV1, + }) + // verify signature type + const sigBytes = utils.arrayify(order.makerWalletSignature!) + expect(sigBytes.length).eq(66) + expect(sigBytes[65]).eq(SignatureType.WalletBytes32) + // verify random values + expect(order.salt?.toString().length).gt(0) + expect(Number(order.expirationTimeSeconds)).gt(0) + const orderSignDigest = getOrderSignDigest(toRFQOrder(order), chainId, RFQV1[chainId]) + const r = utils.hexlify(sigBytes.slice(0, 32)) + const s = utils.hexlify(sigBytes.slice(32, 64)) + const v = utils.hexlify(sigBytes.slice(64, 65)) + console.log(`r: ${r}`) + console.log(`s: ${s}`) + console.log(`v: ${v}`) + const isValid = await rfqv1.callStatic.isValidSignature( + order.makerAddress, + orderSignDigest, + '0x', + order.makerWalletSignature + ) + console.log(`isValid: ${isValid}`) + expect(isValid).true + }).timeout(360000) + it('Should forward unsigned RFQV1 orders to signing service', async () => { + const url = `http://localhost:3000` + const rfqAddr = RFQV1[chainId] + const order: ExtendedZXOrder = { + protocol: Protocol.RFQV1, + quoteId: `0x123`, + exchangeAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`.toLowerCase(), + feeRecipientAddress: `0x45352`, + senderAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`, + takerAddress: '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', + makerAddress: '0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64'.toLowerCase(), + takerAssetData: assetDataUtils.encodeERC20AssetData(WETH[chainId]), + makerAssetData: assetDataUtils.encodeERC20AssetData(USDT_ADDRESS[chainId]), + takerFee: toBN(0), + makerFee: toBN(0), + takerAssetAddress: WETH[chainId], + makerAssetAddress: USDT_ADDRESS[chainId], + 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 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) + }) +}) diff --git a/test/rfqv2.spec.ts b/test/rfqv2.spec.ts new file mode 100644 index 0000000..c9f7ecf --- /dev/null +++ b/test/rfqv2.spec.ts @@ -0,0 +1,255 @@ +import { ethers, network } from 'hardhat' +import { Wallet, utils, Contract } from 'ethers' +import { updaterStack } from '../src/worker' +import { Protocol } from '../src/types' +import { buildSignedOrder as buildRFQV2SignedOrder } from '../src/signer/rfqv2' +import { ExtendedZXOrder, PermitType, SignatureType, WalletType } from '../src/signer/types' +import { getOfferSignDigest } from '../src/signer/orderHash' +import { BigNumber, toBN } from '../src/utils' +import { ABI, WETH, ZERO } from '@tokenlon/sdk' +import * as crypto from 'crypto' +import { expect } from 'chai' +import { toOffer } from '../src/signer/rfqv2' +import { assetDataUtils } from '0x-v2-order-utils' +import * as nock from 'nock' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { + RFQV2, + USDT_ADDRESS, + callNewOrder, + deployEIP1271Plus191Wallet, + deployERC1271Wallet, + deployMMPV4Wallet, + init, + replaceMarketMakingAddress, + usdtHolders, +} from './utils' + +describe('RFQV2 NewOrder', function () { + const chainId: number = network.config.chainId! + let signer: SignerWithAddress + let rfqv2: Contract + before(async () => { + const signers = await ethers.getSigners() + signer = signers[0] + const usdtHolderAddr = usdtHolders[chainId] + rfqv2 = await ethers.getContractAt('ISignatureValidator', RFQV2[chainId]) + await network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [usdtHolderAddr], + }) + }) + beforeEach(function () { + init(chainId, signer) + }) + it('should sign rfqv2 order by EIP712', async function () { + replaceMarketMakingAddress(chainId, signer.address, updaterStack) + const userAddr = Wallet.createRandom().address.toLowerCase() + const usdt = new ethers.Contract(USDT_ADDRESS[chainId], ABI.IERC20, ethers.provider) + await usdt.connect(signer).approve(RFQV2[chainId], ethers.constants.MaxUint256) + const order = await callNewOrder({ + chainId: chainId, + base: 'USDT', + quote: 'ETH', + side: 'SELL', + amount: 1, + walletType: WalletType.EOA, + signer: signer, + userAddr: userAddr, + protocol: Protocol.RFQV2, + }) + expect(order).is.not.null + expect(order.protocol).eq(Protocol.RFQV2) + expect(order.quoteId).eq('1--echo-testing-8888') + expect(order.makerAddress).eq(signer.address.toLowerCase()) + expect(order.makerAssetAmount).eq('1000000000000000000') + expect(order.makerAssetAddress).eq(WETH[chainId].toLowerCase()) + expect( + order.makerAssetData, + `0xf47261b0000000000000000000000000${WETH[chainId].toLowerCase().slice(2)}` + ) + expect(order.takerAddress).eq(userAddr) + expect(order.takerAssetAmount).eq('1000000') + expect(order.takerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) + expect( + order.takerAssetData, + `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` + ) + expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') + expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') + expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') + // The following fields are to be compatible `Order` struct. + expect(order.makerFee).eq('0') + expect(order.takerFee).eq('0') + // verify signature type + const sigBytes = utils.arrayify(order.makerWalletSignature!) + expect(sigBytes.length).eq(66) + expect(sigBytes[65]).eq(SignatureType.EIP712) + // verify random values + expect(order.salt?.toString().length).gt(0) + expect(Number(order.expirationTimeSeconds)).gt(0) + // verify signature + const isValid = await rfqv2.callStatic.isValidSignature( + signer.address, + getOfferSignDigest(toOffer(order), chainId, RFQV2[chainId]), + '0x', + order.makerWalletSignature + ) + expect(isValid).true + }) + it('should sign rfqv2 order for MMPv4', async () => { + const [deployer] = await ethers.getSigners() + const privateKey = crypto.randomBytes(32) + const user = new ethers.Wallet(privateKey, ethers.provider) + const userAddr = user.address.toLowerCase() + const mmpSigner = Wallet.createRandom() + console.log(`mmpSigner: ${mmpSigner.address}`) + const mmproxy = await deployMMPV4Wallet(mmpSigner, deployer) + replaceMarketMakingAddress(chainId, mmproxy.address, updaterStack) + const order = await callNewOrder({ + chainId: chainId, + base: 'ETH', + quote: 'USDT', + side: 'SELL', + amount: 0.1, + walletType: WalletType.MMP_VERSION_4, + signer: mmpSigner, + userAddr: userAddr, + protocol: Protocol.RFQV2, + }) + // taker asset would be a ZERO address in RFQV2 protocol + expect(order.takerAssetAddress).eq(ZERO[chainId].toLowerCase()) + expect(order.takerAssetData).eq( + `0xf47261b0000000000000000000000000${ZERO[chainId].toLowerCase().slice(2)}` + ) + // verify signature type + const sigBytes = utils.arrayify(order.makerWalletSignature!) + expect(sigBytes.length).eq(88) + expect(sigBytes[87]).eq(SignatureType.Wallet) + // verify random values + expect(order.salt?.toString().length).gt(0) + expect(Number(order.expirationTimeSeconds)).gt(0) + const orderSignDigest = getOfferSignDigest(toOffer(order), chainId, RFQV2[chainId]) + const isValid = await rfqv2.callStatic.isValidSignature( + order.makerAddress, + orderSignDigest, + '0x', + order.makerWalletSignature + ) + expect(isValid).true + }).timeout(360000) + it('should sign rfqv2 order for a ERC1271_EIP712_EIP191 MMP contract', async () => { + const [deployer] = await ethers.getSigners() + const user = Wallet.createRandom() + const userAddr = user.address.toLowerCase() + const allowSigner = Wallet.createRandom() + const walletContract = await deployEIP1271Plus191Wallet(allowSigner, deployer) + replaceMarketMakingAddress(chainId, walletContract.address, updaterStack) + const order = await callNewOrder({ + base: 'ETH', + quote: 'USDT', + side: 'SELL', + amount: 0.1, + walletType: WalletType.ERC1271_EIP712_EIP191, + signer: allowSigner, + chainId: chainId, + userAddr: userAddr, + protocol: Protocol.RFQV2, + }) + + // verify signature type + const sigBytes = utils.arrayify(order.makerWalletSignature!) + expect(sigBytes.length).eq(66) + expect(sigBytes[65]).eq(SignatureType.WalletBytes32) + // verify signature + const isValid = await rfqv2.callStatic.isValidSignature( + order.makerAddress, + getOfferSignDigest(toOffer(order), chainId, RFQV2[chainId]), + '0x', + order.makerWalletSignature + ) + expect(isValid).true + }).timeout(360000) + it('should sign rfqv2 order for a ERC1271_EIP712 MMP contract', async () => { + const [deployer] = await ethers.getSigners() + const user = Wallet.createRandom() + const userAddr = user.address.toLowerCase() + const allowSigner = Wallet.createRandom() + const walletContract = await deployERC1271Wallet(allowSigner, deployer) + replaceMarketMakingAddress(chainId, walletContract.address, updaterStack) + const order = await callNewOrder({ + walletType: WalletType.ERC1271_EIP712, + signer: allowSigner, + chainId: chainId, + base: 'ETH', + quote: 'USDT', + side: 'SELL', + amount: 0.1, + userAddr: userAddr, + protocol: Protocol.RFQV2, + }) + // verify signature type + const sigBytes = utils.arrayify(order.makerWalletSignature!) + expect(sigBytes.length).eq(66) + expect(sigBytes[65]).eq(SignatureType.WalletBytes32) + // verify signature + const isValid = await rfqv2.callStatic.isValidSignature( + order.makerAddress, + getOfferSignDigest(toOffer(order), chainId, RFQV2[chainId]), + '0x', + order.makerWalletSignature + ) + expect(isValid).true + }).timeout(360000) + it('Should forward unsigned RFQV2 orders to signing service', async () => { + const url = `http://localhost:3000` + const rfqV2Addr = RFQV2[chainId] + const order: ExtendedZXOrder = { + protocol: Protocol.RFQV2, + quoteId: `0x123`, + exchangeAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`.toLowerCase(), + feeRecipientAddress: `0x45352`, + senderAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`, + takerAddress: '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', + makerAddress: '0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64'.toLowerCase(), + takerAssetData: assetDataUtils.encodeERC20AssetData(WETH[chainId]), + makerAssetData: assetDataUtils.encodeERC20AssetData(USDT_ADDRESS[chainId]), + takerFee: toBN(0), + makerFee: toBN(0), + takerAssetAddress: WETH[chainId], + makerAssetAddress: USDT_ADDRESS[chainId], + 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) + }) +}) diff --git a/test/utils.ts b/test/utils.ts new file mode 100644 index 0000000..29896b7 --- /dev/null +++ b/test/utils.ts @@ -0,0 +1,241 @@ +import { ethers } from 'hardhat' +import { BigNumber } from '0x-v2-utils' +import { Order as ZXOrder } from '0x-v2-order-utils' +import { Updater } from '../src/worker' +import { WETH } from '@tokenlon/sdk' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { Contract, Wallet } from 'ethers' +import { Protocol } from '../src/types' +import { WalletType } from '../src/signer/types' +import { Order, newOrder } from '../src/handler/newOrder' +import { updaterStack } from '../src/worker' +import { NULL_ADDRESS } from '../src/constants' + +export const WALLET_TYPE_MAGIC_VALUE = ethers.utils.keccak256( + Buffer.from('isValidWalletSignature(bytes32,address,bytes)') +) + +export const RFQV2: Record = { + 1: '0x91C986709Bb4fE0763edF8E2690EE9d5019Bea4a', + 5: '0xaE5FDd548E5B107C54E5c0D36952fB8a089f10C7', +} + +export const RFQV1: Record = { + 1: '0xfD6C2d2499b1331101726A8AC68CCc9Da3fAB54F', + 5: '0x117CAf73eB142eDC431E707DC33D4dfeF7c5BAd0', +} + +export const usdtHolders = { + 1: '0x15abb66bA754F05cBC0165A64A11cDed1543dE48', + 5: '0x031BBFB9379c4e6E3F42fb93a9f09C060c7fA037', +} + +export const USDT_ADDRESS: Record = { + 1: '0xdac17f958d2ee523a2206206994597c13d831ec7', + 5: '0xa93ef9215b907c19e739e2214e1aa5412a0401b5', +} + +export const replaceMarketMakingAddress = ( + chainId: number, + address: string, + updaterStack: Record +): void => { + const mockMarkerMakerConfigUpdater = new Updater({ + name: 'mockMarkerMakerConfigUpdater', + updater() { + return Promise.resolve({}) + }, + }) + const cacheResult = { + mmId: 1, + mmProxyContractAddress: address.toLowerCase(), + tokenlonExchangeContractAddress: '0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491', + exchangeContractAddress: '0x30589010550762d2f0d06f650d8e8b6ade6dbf4b', + userProxyContractAddress: '0x25657705a6be20511687d483f2fccfb2d92f6033', + wethContractAddress: WETH[chainId].toLowerCase(), + orderExpirationSeconds: 600, + feeFactor: 30, + addressBookV5: { + Tokenlon: '0x085966eE3E32A0Da16467569512535D38626B547', + PMM: '0x7bd7d025D4231aAD1233967b527FFd7416410257', + AMMWrapper: '0xCF011536f10e85e376E70905EED4CA9eA8Cded34', + RFQ: RFQV1[chainId], + RFQV2: RFQV2[chainId], + }, + } + mockMarkerMakerConfigUpdater.cacheResult = cacheResult + updaterStack['markerMakerConfigUpdater'] = mockMarkerMakerConfigUpdater +} + +export const callNewOrder = async ({ + chainId, + base, + quote, + side, + amount, + signer, + userAddr, + protocol, + walletType, + makerAddress, + payload, +}: { + chainId: number + base: string + quote: string + side: 'SELL' | 'BUY' + amount: number + signer: SignerWithAddress | Wallet + userAddr: string + protocol: Protocol | string + walletType?: WalletType + makerAddress?: string + payload?: string +}): Promise => { + const signedOrderResp = await newOrder({ + walletType: walletType, + signer: signer, + chainID: chainId, + quoter: { + getPrice: () => { + return Promise.resolve({ + result: true, + exchangeable: true, + minAmount: 0, + maxAmount: 1000, + makerAddress: makerAddress, + price: 1, + quoteId: 'echo-testing-8888', + payload: payload, + }) + }, + }, + query: { + base: base, + quote: quote, + side: side, + amount: amount, + uniqId: 'testing-1111', + userAddr: userAddr, + protocol: protocol, + }, + }) + return signedOrderResp.order as Order +} + +export const deployMMPV4Wallet = async ( + mmpSigner: SignerWithAddress | Wallet, + deployer: SignerWithAddress | Wallet +): Promise => { + const mmproxy: Contract = await ( + await ethers.getContractFactory('MarketMakerProxy', deployer) + ).deploy(mmpSigner.address) + return mmproxy +} + +export const deployERC1271Wallet = async ( + allowSigner: SignerWithAddress | Wallet, + deployer: SignerWithAddress | Wallet +): Promise => { + const erc1271Wallet: Contract = await ( + await ethers.getContractFactory('EIP1271Wallet', deployer) + ).deploy(allowSigner.address) + return erc1271Wallet +} + +export const deployEIP1271Plus191Wallet = async ( + allowSigner: SignerWithAddress | Wallet, + deployer: SignerWithAddress | Wallet +): Promise => { + const erc1271Plus191Wallet: Contract = await ( + await ethers.getContractFactory('EIP1271Plus191Wallet', deployer) + ).deploy(allowSigner.address) + return erc1271Plus191Wallet +} + +export const toZXOrder = (order: Order): ZXOrder => { + const o: ZXOrder = { + makerAddress: order.makerAddress, + makerAssetAmount: new BigNumber(order.makerAssetAmount), + makerAssetData: order.makerAssetData, + makerFee: new BigNumber(order.makerFee), + takerAddress: order.takerAddress, + takerAssetAmount: new BigNumber(order.takerAssetAmount), + takerAssetData: order.takerAssetData, + takerFee: new BigNumber(order.takerFee), + senderAddress: order.senderAddress, + feeRecipientAddress: order.feeRecipientAddress, + expirationTimeSeconds: new BigNumber(order.expirationTimeSeconds), + exchangeAddress: order.exchangeAddress, + salt: new BigNumber(order.salt!.toString()), + } + return o +} + +export const init = (chainId: number, signer: SignerWithAddress | Wallet): void => { + const mockMarkerMakerConfigUpdater = new Updater({ + name: 'mockMarkerMakerConfigUpdater', + updater() { + return Promise.resolve({}) + }, + }) + mockMarkerMakerConfigUpdater.cacheResult = { + mmId: 1, + mmProxyContractAddress: signer.address.toLowerCase(), + tokenlonExchangeContractAddress: '0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491', + exchangeContractAddress: '0x30589010550762d2f0d06f650d8e8b6ade6dbf4b', + userProxyContractAddress: '0x25657705a6be20511687d483f2fccfb2d92f6033', + wethContractAddress: WETH[chainId].toLowerCase(), + orderExpirationSeconds: 600, + feeFactor: 30, + addressBookV5: { + Tokenlon: '0x085966eE3E32A0Da16467569512535D38626B547', + PMM: '0x7bd7d025D4231aAD1233967b527FFd7416410257', + AMMWrapper: '0xCF011536f10e85e376E70905EED4CA9eA8Cded34', + RFQ: RFQV1[chainId], + RFQV2: RFQV2[chainId], + }, + } + const mockTokenConfigsFromImtokenUpdater = new Updater({ + name: 'mockTokenConfigsFromImtokenUpdater', + updater() { + return Promise.resolve({}) + }, + }) + mockTokenConfigsFromImtokenUpdater.cacheResult = [] + const mockTokenListUpdate = new Updater({ + name: 'mockTokenListUpdate', + updater() { + return Promise.resolve({}) + }, + }) + mockTokenListUpdate.cacheResult = [ + { + symbol: 'ETH', + contractAddress: NULL_ADDRESS, + decimal: 18, + precision: 4, + minTradeAmount: 0.01, + maxTradeAmount: 10, + }, + { + symbol: 'USDT', + contractAddress: USDT_ADDRESS[chainId], + decimal: 6, + precision: 4, + minTradeAmount: 1, + maxTradeAmount: 1000, + }, + ] + const mockPairsFromMMUpdater = new Updater({ + name: 'mockPairsFromMMUpdater', + updater() { + return Promise.resolve({}) + }, + }) + mockPairsFromMMUpdater.cacheResult = ['USDT/ETH'] + updaterStack['tokenListFromImtokenUpdater'] = mockTokenListUpdate + updaterStack['pairsFromMMUpdater'] = mockPairsFromMMUpdater + updaterStack['markerMakerConfigUpdater'] = mockMarkerMakerConfigUpdater + updaterStack['tokenConfigsFromImtokenUpdater'] = mockTokenConfigsFromImtokenUpdater +} diff --git a/test/numbers.spec.ts b/test/utils/numbers.spec.ts similarity index 91% rename from test/numbers.spec.ts rename to test/utils/numbers.spec.ts index cac24e1..db631f2 100644 --- a/test/numbers.spec.ts +++ b/test/utils/numbers.spec.ts @@ -1,5 +1,5 @@ import { assert } from 'chai' -import { fromUnitToDecimalBN, toBN, truncateAmount } from '../src/utils' +import { fromUnitToDecimalBN, toBN, truncateAmount } from '../../src/utils' describe('Numbers', function () { it('.fromUnitToDecimalBN works', function () { diff --git a/test/quoting.spec.ts b/test/utils/quoting.spec.ts similarity index 78% rename from test/quoting.spec.ts rename to test/utils/quoting.spec.ts index 61735d2..0639eeb 100644 --- a/test/quoting.spec.ts +++ b/test/utils/quoting.spec.ts @@ -1,5 +1,5 @@ import { assert } from 'chai' -import { applyFeeToAmount } from '../src/quoting' +import { applyFeeToAmount } from '../../src/quoting' describe('quoting.ts', function () { it('applyFeeToAmount', function () { diff --git a/test/utils.spec.ts b/test/utils/utils.spec.ts similarity index 91% rename from test/utils.spec.ts rename to test/utils/utils.spec.ts index 75a681c..8d213db 100644 --- a/test/utils.spec.ts +++ b/test/utils/utils.spec.ts @@ -1,6 +1,6 @@ import { expect } from 'chai' -import { QueryInterface } from '../src/types' -import { ensureCorrectSymbolCase } from '../src/quoting' +import { QueryInterface } from '../../src/types' +import { ensureCorrectSymbolCase } from '../../src/quoting' const supportTokens = [ { @@ -87,7 +87,7 @@ const supportTokens = [ describe('translateBaseQuote()', function () { it('does not change correct symbol', function () { - let pair: QueryInterface = { base: 'DAI', quote: 'ETH', side: 'BUY' } + const pair: QueryInterface = { base: 'DAI', quote: 'ETH', side: 'BUY' } expect(ensureCorrectSymbolCase(pair, supportTokens)).to.eql({ base: 'DAI', baseAddress: '0x5c964665b6379527b625be996020d861f27aa31d', @@ -98,7 +98,7 @@ describe('translateBaseQuote()', function () { }) it('correct symbol in pair', function () { - let pair: QueryInterface = { base: 'DAI', quote: 'Eth', side: 'BUY' } + const pair: QueryInterface = { base: 'DAI', quote: 'Eth', side: 'BUY' } expect(ensureCorrectSymbolCase(pair, supportTokens)).to.eql({ base: 'DAI', baseAddress: '0x5c964665b6379527b625be996020d861f27aa31d', @@ -109,7 +109,7 @@ describe('translateBaseQuote()', function () { }) it('correct symbol case in pair', function () { - let pair: QueryInterface = { base: 'IMBTC', quote: 'ETH', side: 'BUY' } + const pair: QueryInterface = { base: 'IMBTC', quote: 'ETH', side: 'BUY' } expect(ensureCorrectSymbolCase(pair, supportTokens)).to.eql({ base: 'imBTC', baseAddress: '0x5c964665b6379527b625be996020d861f27aa31d', @@ -120,7 +120,7 @@ describe('translateBaseQuote()', function () { }) it('correct symbol when query by token address', function () { - let pair: QueryInterface = { + const pair: QueryInterface = { base: '', quote: '', baseAddress: '0x5c964665b6379527b625be996020d861f27aa31d', diff --git a/test/validator.spec.ts b/test/utils/validator.spec.ts similarity index 55% rename from test/validator.spec.ts rename to test/utils/validator.spec.ts index 328eff4..99f7640 100644 --- a/test/validator.spec.ts +++ b/test/utils/validator.spec.ts @@ -1,6 +1,6 @@ import { expect } from 'chai' -import { ethers } from 'hardhat' -import { validateNewOrderRequest, validateRequest } from '../src/validations' +import { ethers } from 'ethers' +import { validateNewOrderRequest, validateRequest } from '../../src/validations' describe('Validator', function () { it('validateRequest', function () { @@ -15,9 +15,8 @@ describe('Validator', function () { }) it('validateNewOrderRequest', function () { - expect(validateNewOrderRequest(1, 'foobar', ethers.Wallet.createRandom().address)).to.be.eq(null) - expect(validateNewOrderRequest(1, 'foobar', 'baz')).to.be.eq( - `userAddress:baz is not a valid address` - ) + const address = ethers.Wallet.createRandom().address + expect(validateNewOrderRequest(1, 'foobar', address)).eq(null) + expect(validateNewOrderRequest(1, 'foobar', 'baz')).eq('userAddress:baz is not a valid address') }) }) From 3393b8f44d80de62c39e48e99452c46e9edd8b79 Mon Sep 17 00:00:00 2001 From: BenjaminLu Date: Thu, 14 Sep 2023 01:08:25 +0800 Subject: [PATCH 2/4] fix: bumping version --- package.json | 2 +- src/handler/version.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 65b9877..ee1fa2c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@consenlabs/tokenlon-mmsk", - "version": "5.3.2", + "version": "5.3.3", "description": "Tokenlon market maker server kit", "author": "imToken PTE. LTD.", "license": "MIT", diff --git a/src/handler/version.ts b/src/handler/version.ts index 1aaeef1..70cab31 100644 --- a/src/handler/version.ts +++ b/src/handler/version.ts @@ -1,4 +1,4 @@ -export const VERSION = '5.3.2' +export const VERSION = '5.3.3' export const version = (ctx) => { ctx.body = { From 2b2b652e5891cda03ad3eb902679894d96643361 Mon Sep 17 00:00:00 2001 From: BenjaminLu Date: Thu, 14 Sep 2023 16:50:28 +0800 Subject: [PATCH 3/4] fix: validating order fields in expectOrder() --- package-lock.json | 4 +-- test/amm.spec.ts | 88 ++++++++++++++++------------------------------ test/pmm.spec.ts | 54 ++++++++++++++-------------- test/rfqv1.spec.ts | 85 ++++++++++++++++++++++++++++---------------- test/rfqv2.spec.ts | 87 ++++++++++++++++++++++++++++++--------------- test/utils.ts | 61 ++++++++++++++++++++++++++++++++ 6 files changed, 235 insertions(+), 144 deletions(-) diff --git a/package-lock.json b/package-lock.json index 63d5229..2a9f323 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@consenlabs/tokenlon-mmsk", - "version": "5.3.2", + "version": "5.3.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@consenlabs/tokenlon-mmsk", - "version": "5.3.2", + "version": "5.3.3", "license": "MIT", "dependencies": { "@0x/contract-addresses": "^4.11.0", diff --git a/test/amm.spec.ts b/test/amm.spec.ts index f88c41e..5e0f0aa 100644 --- a/test/amm.spec.ts +++ b/test/amm.spec.ts @@ -3,11 +3,13 @@ import { Wallet, utils } from 'ethers' import { Protocol } from '../src/types' import { WalletType } from '../src/signer/types' import * as ethUtils from 'ethereumjs-util' -import { WETH } from '@tokenlon/sdk' +import { WETH, ZERO } from '@tokenlon/sdk' import { expect } from 'chai' import { generateSaltWithFeeFactor } from '../src/signer/pmmv5' import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' -import { USDT_ADDRESS, callNewOrder, init } from './utils' +import { USDT_ADDRESS, callNewOrder, expectOrder, getMarketMakingInfo, init } from './utils' +import { assetDataUtils } from '0x-v2-order-utils' +import { FEE_RECIPIENT_ADDRESS } from '../src/constants' describe('AMM NewOrder', function () { const chainId: number = network.config.chainId! @@ -20,6 +22,7 @@ describe('AMM NewOrder', function () { init(chainId, signer) }) it('should create ammv1 order by uniswap v2', async function () { + const marketMakingInfo = getMarketMakingInfo() const ammAddr = '0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852' const order = await callNewOrder({ chainId: chainId, @@ -32,36 +35,21 @@ describe('AMM NewOrder', function () { protocol: Protocol.AMMV1, makerAddress: ammAddr, }) - 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') - expect(order.makerAddress).eq('0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852') - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect(order.makerAssetData).eq( - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq('0x25657705a6be20511687d483f2fccfb2d92f6033') - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq('0x0000000000000000000000000000000000000000') - expect(order.takerAssetData).eq( - '0xf47261b00000000000000000000000000000000000000000000000000000000000000000' - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - // verify signature length, the signature is generated ramdonly. - expect(order.makerWalletSignature?.length).eq(40) - // verify random values - expect(order.salt?.toString().length).gt(0) - expect(Number(order.expirationTimeSeconds)).gt(0) + expectOrder({ + order: order, + expectedProtocol: Protocol.AMMV1, + expectedTakerAddress: marketMakingInfo.userProxyContractAddress, + expectedMakerAddress: ammAddr, + expectedTakerAssetAddress: ZERO[chainId], + expectedMakerAssetAddress: USDT_ADDRESS[chainId], + expectedTakerAssetAmount: utils.parseEther('0.1').toString(), + expectedMakerAssetAmount: utils.parseUnits('0.1', 6).toString(), + expectedFeeRecipient: FEE_RECIPIENT_ADDRESS, + expectedSenderAddress: marketMakingInfo.tokenlonExchangeContractAddress, + }) }) it('should create ammv2 order by uniswap v2', async function () { + const marketMakingInfo = getMarketMakingInfo() const ammAddr = '0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852' const payload = Buffer.from( JSON.stringify({ @@ -80,32 +68,18 @@ describe('AMM NewOrder', function () { makerAddress: ammAddr, payload: payload, }) - expect(order).is.not.null - expect(order.protocol).eq(Protocol.AMMV2) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq('0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852') - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect(order.makerAssetData).eq( - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq('0x25657705a6be20511687d483f2fccfb2d92f6033') - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq('0x0000000000000000000000000000000000000000') - expect(order.takerAssetData).eq( - '0xf47261b00000000000000000000000000000000000000000000000000000000000000000' - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - // verify signature length, the signature is generated ramdonly. - expect(order.makerWalletSignature?.length).eq(40) - // verify random values - expect(order.salt?.toString().length).gt(0) - expect(Number(order.expirationTimeSeconds)).gt(0) + expectOrder({ + order: order, + expectedProtocol: Protocol.AMMV2, + expectedTakerAddress: marketMakingInfo.userProxyContractAddress, + expectedMakerAddress: ammAddr, + expectedTakerAssetAddress: ZERO[chainId], + expectedMakerAssetAddress: USDT_ADDRESS[chainId], + expectedTakerAssetAmount: utils.parseEther('0.1').toString(), + expectedMakerAssetAmount: utils.parseUnits('0.1', 6).toString(), + expectedFeeRecipient: FEE_RECIPIENT_ADDRESS, + expectedSenderAddress: marketMakingInfo.tokenlonExchangeContractAddress, + }) expect(order.payload).eq(payload) }) describe('handle token precision and decimals', () => { @@ -124,7 +98,7 @@ describe('AMM NewOrder', function () { expect(order).is.not.null expect(order.quoteId).eq('1--echo-testing-8888') expect(order.makerWalletSignature?.toString().slice(-1)).eq('4') - expect(order.takerAssetData.slice(34)).eq(USDT_ADDRESS[chainId].toLowerCase().slice(2)) + expect(order.takerAssetData).eq(assetDataUtils.encodeERC20AssetData(USDT_ADDRESS[chainId])) expect(order.takerAssetAmount).eq(utils.parseUnits('0.1114', 6).toString()) expect(order.makerAssetAmount).eq(utils.parseEther('0.1114').toString()) }) diff --git a/test/pmm.spec.ts b/test/pmm.spec.ts index 5ffe8f8..b74ba67 100644 --- a/test/pmm.spec.ts +++ b/test/pmm.spec.ts @@ -15,6 +15,8 @@ import { WALLET_TYPE_MAGIC_VALUE, callNewOrder, deployMMPV4Wallet, + expectOrder, + getMarketMakingInfo, init, replaceMarketMakingAddress, toZXOrder, @@ -53,6 +55,7 @@ describe('PMM NewOrder', function () { ) }) it('should sign pmmv5 order by EOA', async function () { + const marketMakingInfo = getMarketMakingInfo() replaceMarketMakingAddress(chainId, signer.address, updaterStack) const userAddr = Wallet.createRandom().address.toLowerCase() const order = await callNewOrder({ @@ -66,32 +69,18 @@ describe('PMM NewOrder', function () { signer, walletType: WalletType.EOA, }) - expect(order).is.not.null - expect(order.protocol).eq(Protocol.PMMV5) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq(signer.address.toLowerCase()) - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect(order.makerAssetData).eq( - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq('0x7bd7d025d4231aad1233967b527ffd7416410257') - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq(WETH[chainId].toLowerCase()) - expect(order.takerAssetData).eq( - `0xf47261b0000000000000000000000000${WETH[chainId].toLowerCase().slice(2)}` - ) - expect(order.senderAddress).eq('0x7bd7d025d4231aad1233967b527ffd7416410257') - expect(order.feeRecipientAddress).eq(userAddr) - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') - // verify signature type - expect(order.makerWalletSignature?.slice(-1)).eq('3') - // verify random values - expect(order.salt?.toString().length).gt(0) - expect(Number(order.expirationTimeSeconds)).gt(0) + expectOrder({ + order: order, + expectedProtocol: Protocol.PMMV5, + expectedTakerAddress: marketMakingInfo.addressBookV5.PMM, + expectedMakerAddress: signer.address, + expectedTakerAssetAddress: WETH[chainId], + expectedMakerAssetAddress: USDT_ADDRESS[chainId], + expectedTakerAssetAmount: utils.parseEther('0.1').toString(), + expectedMakerAssetAmount: utils.parseUnits('0.1', 6).toString(), + expectedFeeRecipient: userAddr, + expectedSenderAddress: marketMakingInfo.addressBookV5.PMM, + }) const zxOrder = toZXOrder(order) const orderHashBuffer = eip712Utils.structHash(EIP712_ORDER_SCHEMA, zxOrder) const orderHash = '0x' + orderHashBuffer.toString('hex') @@ -110,6 +99,7 @@ describe('PMM NewOrder', function () { expect(recovered.toLowerCase()).eq(signer.address.toLowerCase()) }) it('should sign pmmv5 order for MMPv4', async function () { + const marketMakingInfo = getMarketMakingInfo() const usdtHolder = await ethers.provider.getSigner(usdtHolders[chainId]) const usdt = await ethers.getContractAt(ABI.IERC20, USDT_ADDRESS[chainId]) const mmpSigner = Wallet.createRandom() @@ -130,6 +120,18 @@ describe('PMM NewOrder', function () { makerAddress: mmproxy.address, walletType: WalletType.MMP_VERSION_4, }) + expectOrder({ + order: order, + expectedProtocol: Protocol.PMMV5, + expectedTakerAddress: marketMakingInfo.addressBookV5.PMM, + expectedMakerAddress: mmproxy.address, + expectedTakerAssetAddress: WETH[chainId], + expectedMakerAssetAddress: USDT_ADDRESS[chainId], + expectedTakerAssetAmount: utils.parseEther('0.1').toString(), + expectedMakerAssetAmount: utils.parseUnits('0.1', 6).toString(), + expectedFeeRecipient: userAddr, + expectedSenderAddress: marketMakingInfo.addressBookV5.PMM, + }) console.log(`order.makerWalletSignature: ${order.makerWalletSignature}`) const magicValue = await mmproxy.callStatic.isValidSignature( orderHashUtils.getOrderHashHex(toZXOrder(order)), diff --git a/test/rfqv1.spec.ts b/test/rfqv1.spec.ts index 566385a..f8ae342 100644 --- a/test/rfqv1.spec.ts +++ b/test/rfqv1.spec.ts @@ -20,10 +20,13 @@ import { deployEIP1271Plus191Wallet, deployERC1271Wallet, deployMMPV4Wallet, + expectOrder, + getMarketMakingInfo, init, replaceMarketMakingAddress, usdtHolders, } from './utils' +import { FEE_RECIPIENT_ADDRESS } from '../src/constants' describe('RFQV1 NewOrder', function () { const chainId: number = network.config.chainId! @@ -43,6 +46,7 @@ describe('RFQV1 NewOrder', function () { init(chainId, signer) }) it('should sign rfqv1 order by EIP712', async function () { + const marketMakingInfo = getMarketMakingInfo() replaceMarketMakingAddress(chainId, signer.address, updaterStack) const userAddr = Wallet.createRandom().address.toLowerCase() const order = await callNewOrder({ @@ -56,30 +60,18 @@ describe('RFQV1 NewOrder', function () { signer: signer, protocol: Protocol.RFQV1, }) - console.log(order) - expect(order).is.not.null - expect(order.protocol).eq(Protocol.RFQV1) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq(signer.address.toLowerCase()) - expect(order.makerAssetAmount).eq('100000') - expect(order.makerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect( - order.makerAssetData, - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq(userAddr) - expect(order.takerAssetAmount).eq('100000000000000000') - expect(order.takerAssetAddress).eq(WETH[chainId].toLowerCase()) - expect( - order.takerAssetData, - `0xf47261b0000000000000000000000000${WETH[chainId].toLowerCase().slice(2)}` - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') + expectOrder({ + order: order, + expectedProtocol: Protocol.RFQV1, + expectedTakerAddress: userAddr, + expectedMakerAddress: signer.address, + expectedTakerAssetAddress: WETH[chainId], + expectedMakerAssetAddress: USDT_ADDRESS[chainId], + expectedTakerAssetAmount: utils.parseEther('0.1').toString(), + expectedMakerAssetAmount: utils.parseUnits('0.1', 6).toString(), + expectedFeeRecipient: FEE_RECIPIENT_ADDRESS, + expectedSenderAddress: marketMakingInfo.tokenlonExchangeContractAddress, + }) // verify signature type const sigBytes = utils.arrayify(order.makerWalletSignature!) expect(sigBytes.length).eq(98) @@ -98,6 +90,7 @@ describe('RFQV1 NewOrder', function () { expect(Number(order.expirationTimeSeconds)).gt(0) }) it('should sign rfqv1 order for MMPv4', async () => { + const marketMakingInfo = getMarketMakingInfo() const user = Wallet.createRandom() const userAddr = user.address.toLowerCase() const [deployer] = await ethers.getSigners() @@ -118,6 +111,18 @@ describe('RFQV1 NewOrder', function () { chainId: chainId, protocol: Protocol.RFQV1, }) + expectOrder({ + order: order, + expectedProtocol: Protocol.RFQV1, + expectedTakerAddress: userAddr, + expectedMakerAddress: mmproxy.address, + expectedTakerAssetAddress: WETH[chainId], + expectedMakerAssetAddress: USDT_ADDRESS[chainId], + expectedTakerAssetAmount: utils.parseEther('0.1').toString(), + expectedMakerAssetAmount: utils.parseUnits('0.1', 6).toString(), + expectedFeeRecipient: FEE_RECIPIENT_ADDRESS, + expectedSenderAddress: marketMakingInfo.tokenlonExchangeContractAddress, + }) // verify signature type const sigBytes = utils.arrayify(order.makerWalletSignature!) expect(sigBytes.length).eq(88) @@ -136,6 +141,7 @@ describe('RFQV1 NewOrder', function () { expect(isValid).true }).timeout(360000) it('should sign rfqv1 order for a ERC1271_EIP712_EIP191 MMP contract', async () => { + const marketMakingInfo = getMarketMakingInfo() const [deployer] = await ethers.getSigners() const privateKey = crypto.randomBytes(32) const user = new ethers.Wallet(privateKey, ethers.provider) @@ -156,6 +162,18 @@ describe('RFQV1 NewOrder', function () { signer: allowSigner, protocol: Protocol.RFQV1, }) + expectOrder({ + order: order, + expectedProtocol: Protocol.RFQV1, + expectedTakerAddress: userAddr, + expectedMakerAddress: walletContract.address, + expectedTakerAssetAddress: WETH[chainId], + expectedMakerAssetAddress: USDT_ADDRESS[chainId], + expectedTakerAssetAmount: utils.parseEther('0.1').toString(), + expectedMakerAssetAmount: utils.parseUnits('0.1', 6).toString(), + expectedFeeRecipient: FEE_RECIPIENT_ADDRESS, + expectedSenderAddress: marketMakingInfo.tokenlonExchangeContractAddress, + }) // verify signature type const sigBytes = utils.arrayify(order.makerWalletSignature!) expect(sigBytes.length).eq(66) @@ -174,6 +192,7 @@ describe('RFQV1 NewOrder', function () { expect(isValid).true }).timeout(360000) it('should sign rfqv1 order for a ERC1271_EIP712 MMP contract', async () => { + const marketMakingInfo = getMarketMakingInfo() const [deployer] = await ethers.getSigners() const user = Wallet.createRandom() const userAddr = user.address.toLowerCase() @@ -193,6 +212,18 @@ describe('RFQV1 NewOrder', function () { userAddr: userAddr, protocol: Protocol.RFQV1, }) + expectOrder({ + order: order, + expectedProtocol: Protocol.RFQV1, + expectedTakerAddress: userAddr, + expectedMakerAddress: walletContract.address, + expectedTakerAssetAddress: WETH[chainId], + expectedMakerAssetAddress: USDT_ADDRESS[chainId], + expectedTakerAssetAmount: utils.parseEther('0.1').toString(), + expectedMakerAssetAmount: utils.parseUnits('0.1', 6).toString(), + expectedFeeRecipient: FEE_RECIPIENT_ADDRESS, + expectedSenderAddress: marketMakingInfo.tokenlonExchangeContractAddress, + }) // verify signature type const sigBytes = utils.arrayify(order.makerWalletSignature!) expect(sigBytes.length).eq(66) @@ -201,12 +232,6 @@ describe('RFQV1 NewOrder', function () { expect(order.salt?.toString().length).gt(0) expect(Number(order.expirationTimeSeconds)).gt(0) const orderSignDigest = getOrderSignDigest(toRFQOrder(order), chainId, RFQV1[chainId]) - const r = utils.hexlify(sigBytes.slice(0, 32)) - const s = utils.hexlify(sigBytes.slice(32, 64)) - const v = utils.hexlify(sigBytes.slice(64, 65)) - console.log(`r: ${r}`) - console.log(`s: ${s}`) - console.log(`v: ${v}`) const isValid = await rfqv1.callStatic.isValidSignature( order.makerAddress, orderSignDigest, diff --git a/test/rfqv2.spec.ts b/test/rfqv2.spec.ts index c9f7ecf..82f73b1 100644 --- a/test/rfqv2.spec.ts +++ b/test/rfqv2.spec.ts @@ -20,10 +20,13 @@ import { deployEIP1271Plus191Wallet, deployERC1271Wallet, deployMMPV4Wallet, + expectOrder, + getMarketMakingInfo, init, replaceMarketMakingAddress, usdtHolders, } from './utils' +import { FEE_RECIPIENT_ADDRESS } from '../src/constants' describe('RFQV2 NewOrder', function () { const chainId: number = network.config.chainId! @@ -44,6 +47,7 @@ describe('RFQV2 NewOrder', function () { }) it('should sign rfqv2 order by EIP712', async function () { replaceMarketMakingAddress(chainId, signer.address, updaterStack) + const marketMakingInfo = getMarketMakingInfo() const userAddr = Wallet.createRandom().address.toLowerCase() const usdt = new ethers.Contract(USDT_ADDRESS[chainId], ABI.IERC20, ethers.provider) await usdt.connect(signer).approve(RFQV2[chainId], ethers.constants.MaxUint256) @@ -58,29 +62,18 @@ describe('RFQV2 NewOrder', function () { userAddr: userAddr, protocol: Protocol.RFQV2, }) - expect(order).is.not.null - expect(order.protocol).eq(Protocol.RFQV2) - expect(order.quoteId).eq('1--echo-testing-8888') - expect(order.makerAddress).eq(signer.address.toLowerCase()) - expect(order.makerAssetAmount).eq('1000000000000000000') - expect(order.makerAssetAddress).eq(WETH[chainId].toLowerCase()) - expect( - order.makerAssetData, - `0xf47261b0000000000000000000000000${WETH[chainId].toLowerCase().slice(2)}` - ) - expect(order.takerAddress).eq(userAddr) - expect(order.takerAssetAmount).eq('1000000') - expect(order.takerAssetAddress).eq(USDT_ADDRESS[chainId].toLowerCase()) - expect( - order.takerAssetData, - `0xf47261b0000000000000000000000000${USDT_ADDRESS[chainId].toLowerCase().slice(2)}` - ) - expect(order.senderAddress).eq('0xd489f1684cf5e78d933e254bd7ac8a9a6a70d491') - expect(order.feeRecipientAddress).eq('0xb9e29984fe50602e7a619662ebed4f90d93824c7') - expect(order.exchangeAddress).eq('0x30589010550762d2f0d06f650d8e8b6ade6dbf4b') - // The following fields are to be compatible `Order` struct. - expect(order.makerFee).eq('0') - expect(order.takerFee).eq('0') + expectOrder({ + order: order, + expectedProtocol: Protocol.RFQV2, + expectedTakerAddress: userAddr, + expectedMakerAddress: signer.address, + expectedTakerAssetAddress: USDT_ADDRESS[chainId], + expectedMakerAssetAddress: WETH[chainId], + expectedTakerAssetAmount: utils.parseUnits('1', 6).toString(), + expectedMakerAssetAmount: utils.parseEther('1').toString(), + expectedFeeRecipient: FEE_RECIPIENT_ADDRESS, + expectedSenderAddress: marketMakingInfo.tokenlonExchangeContractAddress, + }) // verify signature type const sigBytes = utils.arrayify(order.makerWalletSignature!) expect(sigBytes.length).eq(66) @@ -106,6 +99,7 @@ describe('RFQV2 NewOrder', function () { console.log(`mmpSigner: ${mmpSigner.address}`) const mmproxy = await deployMMPV4Wallet(mmpSigner, deployer) replaceMarketMakingAddress(chainId, mmproxy.address, updaterStack) + const marketMakingInfo = getMarketMakingInfo() const order = await callNewOrder({ chainId: chainId, base: 'ETH', @@ -118,10 +112,18 @@ describe('RFQV2 NewOrder', function () { protocol: Protocol.RFQV2, }) // taker asset would be a ZERO address in RFQV2 protocol - expect(order.takerAssetAddress).eq(ZERO[chainId].toLowerCase()) - expect(order.takerAssetData).eq( - `0xf47261b0000000000000000000000000${ZERO[chainId].toLowerCase().slice(2)}` - ) + expectOrder({ + order: order, + expectedProtocol: Protocol.RFQV2, + expectedTakerAddress: userAddr, + expectedMakerAddress: mmproxy.address, + expectedTakerAssetAddress: ZERO[chainId], + expectedMakerAssetAddress: USDT_ADDRESS[chainId], + expectedTakerAssetAmount: utils.parseEther('0.1').toString(), + expectedMakerAssetAmount: utils.parseUnits('0.1', 6).toString(), + expectedFeeRecipient: FEE_RECIPIENT_ADDRESS, + expectedSenderAddress: marketMakingInfo.tokenlonExchangeContractAddress, + }) // verify signature type const sigBytes = utils.arrayify(order.makerWalletSignature!) expect(sigBytes.length).eq(88) @@ -145,6 +147,7 @@ describe('RFQV2 NewOrder', function () { const allowSigner = Wallet.createRandom() const walletContract = await deployEIP1271Plus191Wallet(allowSigner, deployer) replaceMarketMakingAddress(chainId, walletContract.address, updaterStack) + const marketMakingInfo = getMarketMakingInfo() const order = await callNewOrder({ base: 'ETH', quote: 'USDT', @@ -157,6 +160,19 @@ describe('RFQV2 NewOrder', function () { protocol: Protocol.RFQV2, }) + expectOrder({ + order: order, + expectedProtocol: Protocol.RFQV2, + expectedTakerAddress: userAddr, + expectedMakerAddress: walletContract.address, + expectedTakerAssetAddress: ZERO[chainId], + expectedMakerAssetAddress: USDT_ADDRESS[chainId], + expectedTakerAssetAmount: utils.parseEther('0.1').toString(), + expectedMakerAssetAmount: utils.parseUnits('0.1', 6).toString(), + expectedFeeRecipient: FEE_RECIPIENT_ADDRESS, + expectedSenderAddress: marketMakingInfo.tokenlonExchangeContractAddress, + }) + // verify signature type const sigBytes = utils.arrayify(order.makerWalletSignature!) expect(sigBytes.length).eq(66) @@ -177,6 +193,7 @@ describe('RFQV2 NewOrder', function () { const allowSigner = Wallet.createRandom() const walletContract = await deployERC1271Wallet(allowSigner, deployer) replaceMarketMakingAddress(chainId, walletContract.address, updaterStack) + const marketMakingInfo = getMarketMakingInfo() const order = await callNewOrder({ walletType: WalletType.ERC1271_EIP712, signer: allowSigner, @@ -188,6 +205,18 @@ describe('RFQV2 NewOrder', function () { userAddr: userAddr, protocol: Protocol.RFQV2, }) + expectOrder({ + order: order, + expectedProtocol: Protocol.RFQV2, + expectedTakerAddress: userAddr, + expectedMakerAddress: walletContract.address, + expectedTakerAssetAddress: ZERO[chainId], + expectedMakerAssetAddress: USDT_ADDRESS[chainId], + expectedTakerAssetAmount: utils.parseEther('0.1').toString(), + expectedMakerAssetAmount: utils.parseUnits('0.1', 6).toString(), + expectedFeeRecipient: FEE_RECIPIENT_ADDRESS, + expectedSenderAddress: marketMakingInfo.tokenlonExchangeContractAddress, + }) // verify signature type const sigBytes = utils.arrayify(order.makerWalletSignature!) expect(sigBytes.length).eq(66) @@ -212,11 +241,11 @@ describe('RFQV2 NewOrder', function () { senderAddress: `0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64`, takerAddress: '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', makerAddress: '0x86B9F429C3Ef44c599EB560Eb531A0E3f2E36f64'.toLowerCase(), - takerAssetData: assetDataUtils.encodeERC20AssetData(WETH[chainId]), + takerAssetData: assetDataUtils.encodeERC20AssetData(ZERO[chainId]), makerAssetData: assetDataUtils.encodeERC20AssetData(USDT_ADDRESS[chainId]), takerFee: toBN(0), makerFee: toBN(0), - takerAssetAddress: WETH[chainId], + takerAssetAddress: ZERO[chainId], makerAssetAddress: USDT_ADDRESS[chainId], takerAssetAmount: new BigNumber('0x0de0b6b3a7640000'), makerAssetAmount: new BigNumber('0x05f5e100'), diff --git a/test/utils.ts b/test/utils.ts index 29896b7..813d233 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -10,6 +10,10 @@ import { WalletType } from '../src/signer/types' import { Order, newOrder } from '../src/handler/newOrder' import { updaterStack } from '../src/worker' import { NULL_ADDRESS } from '../src/constants' +import * as chai from 'chai' +import { solidity } from 'ethereum-waffle' +chai.use(solidity) +const { expect } = chai export const WALLET_TYPE_MAGIC_VALUE = ethers.utils.keccak256( Buffer.from('isValidWalletSignature(bytes32,address,bytes)') @@ -239,3 +243,60 @@ export const init = (chainId: number, signer: SignerWithAddress | Wallet): void updaterStack['markerMakerConfigUpdater'] = mockMarkerMakerConfigUpdater updaterStack['tokenConfigsFromImtokenUpdater'] = mockTokenConfigsFromImtokenUpdater } + +export const getMarketMakingInfo = (): any => { + return updaterStack['markerMakerConfigUpdater'].cacheResult +} + +export const expectOrder = ({ + order, + expectedProtocol, + expectedTakerAddress, + expectedMakerAddress, + expectedTakerAssetAddress, + expectedMakerAssetAddress, + expectedTakerAssetAmount, + expectedMakerAssetAmount, + expectedFeeRecipient, + expectedSenderAddress, +}: { + order: Order + expectedProtocol: Protocol + expectedTakerAddress: string + expectedMakerAddress: string + expectedTakerAssetAddress: string + expectedMakerAssetAddress: string + expectedTakerAssetAmount: string + expectedMakerAssetAmount: string + expectedFeeRecipient: string + expectedSenderAddress: string +}): void => { + const cacheResult = updaterStack['markerMakerConfigUpdater'].cacheResult + expect(cacheResult).is.not.null + expect(order).is.not.null + expect(order.protocol).eq(expectedProtocol) + expect(order.quoteId).eq('1--echo-testing-8888') + expect(order.makerAddress).to.hexEqual(expectedMakerAddress) + expect(order.makerAssetAmount).eq(expectedMakerAssetAmount) + expect(order.makerAssetAddress).to.hexEqual(expectedMakerAssetAddress) + expect(order.makerAssetData).eq( + `0xf47261b0000000000000000000000000${expectedMakerAssetAddress.toLowerCase().slice(2)}` + ) + expect(order.takerAddress).to.hexEqual(expectedTakerAddress) + expect(order.takerAssetAmount).eq(expectedTakerAssetAmount) + expect(order.takerAssetAddress).to.hexEqual(expectedTakerAssetAddress) + expect(order.takerAssetData).eq( + `0xf47261b0000000000000000000000000${expectedTakerAssetAddress.toLowerCase().slice(2)}` + ) + expect(order.senderAddress).to.hexEqual(expectedSenderAddress) + expect(order.feeRecipientAddress).to.hexEqual(expectedFeeRecipient) + expect(order.exchangeAddress).to.hexEqual(cacheResult.exchangeContractAddress) + // The following fields are to be compatible `Order` struct. + expect(order.makerFee).eq('0') + expect(order.takerFee).eq('0') + // verify signature length, the signature is generated ramdonly. + expect(order.makerWalletSignature?.length).gt(0) + // verify random values + expect(order.salt?.toString().length).gt(0) + expect(Number(order.expirationTimeSeconds)).gt(0) +} From 9980b10593223c7ec43612929823950d0495881a Mon Sep 17 00:00:00 2001 From: BenjaminLu Date: Thu, 14 Sep 2023 17:04:11 +0800 Subject: [PATCH 4/4] fix: adjusting call stack --- test/pmm.spec.ts | 4 ++-- test/rfqv1.spec.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/pmm.spec.ts b/test/pmm.spec.ts index b74ba67..adddd2f 100644 --- a/test/pmm.spec.ts +++ b/test/pmm.spec.ts @@ -55,8 +55,8 @@ describe('PMM NewOrder', function () { ) }) it('should sign pmmv5 order by EOA', async function () { - const marketMakingInfo = getMarketMakingInfo() replaceMarketMakingAddress(chainId, signer.address, updaterStack) + const marketMakingInfo = getMarketMakingInfo() const userAddr = Wallet.createRandom().address.toLowerCase() const order = await callNewOrder({ chainId: chainId, @@ -99,13 +99,13 @@ describe('PMM NewOrder', function () { expect(recovered.toLowerCase()).eq(signer.address.toLowerCase()) }) it('should sign pmmv5 order for MMPv4', async function () { - const marketMakingInfo = getMarketMakingInfo() const usdtHolder = await ethers.provider.getSigner(usdtHolders[chainId]) const usdt = await ethers.getContractAt(ABI.IERC20, USDT_ADDRESS[chainId]) const mmpSigner = Wallet.createRandom() const [deployer] = await ethers.getSigners() const mmproxy = await deployMMPV4Wallet(mmpSigner, deployer) replaceMarketMakingAddress(chainId, mmproxy.address, updaterStack) + const marketMakingInfo = getMarketMakingInfo() await usdt.connect(usdtHolder).transfer(mmproxy.address, ethers.utils.parseUnits('1000', 6)) const userAddr = Wallet.createRandom().address.toLowerCase() const order = await callNewOrder({ diff --git a/test/rfqv1.spec.ts b/test/rfqv1.spec.ts index f8ae342..0d4f3bc 100644 --- a/test/rfqv1.spec.ts +++ b/test/rfqv1.spec.ts @@ -46,8 +46,8 @@ describe('RFQV1 NewOrder', function () { init(chainId, signer) }) it('should sign rfqv1 order by EIP712', async function () { - const marketMakingInfo = getMarketMakingInfo() replaceMarketMakingAddress(chainId, signer.address, updaterStack) + const marketMakingInfo = getMarketMakingInfo() const userAddr = Wallet.createRandom().address.toLowerCase() const order = await callNewOrder({ chainId: chainId, @@ -90,7 +90,6 @@ describe('RFQV1 NewOrder', function () { expect(Number(order.expirationTimeSeconds)).gt(0) }) it('should sign rfqv1 order for MMPv4', async () => { - const marketMakingInfo = getMarketMakingInfo() const user = Wallet.createRandom() const userAddr = user.address.toLowerCase() const [deployer] = await ethers.getSigners() @@ -100,6 +99,7 @@ describe('RFQV1 NewOrder', function () { console.log(`mmproxy: ${mmproxy.address}`) expect(mmproxy.address).is.not.null replaceMarketMakingAddress(chainId, mmproxy.address, updaterStack) + const marketMakingInfo = getMarketMakingInfo() const order = await callNewOrder({ base: 'ETH', quote: 'USDT', @@ -141,7 +141,6 @@ describe('RFQV1 NewOrder', function () { expect(isValid).true }).timeout(360000) it('should sign rfqv1 order for a ERC1271_EIP712_EIP191 MMP contract', async () => { - const marketMakingInfo = getMarketMakingInfo() const [deployer] = await ethers.getSigners() const privateKey = crypto.randomBytes(32) const user = new ethers.Wallet(privateKey, ethers.provider) @@ -151,6 +150,7 @@ describe('RFQV1 NewOrder', function () { const walletContract = await deployEIP1271Plus191Wallet(allowSigner, deployer) expect(walletContract.address).is.not.null replaceMarketMakingAddress(chainId, walletContract.address, updaterStack) + const marketMakingInfo = getMarketMakingInfo() const order = await callNewOrder({ base: 'ETH', quote: 'USDT', @@ -192,7 +192,6 @@ describe('RFQV1 NewOrder', function () { expect(isValid).true }).timeout(360000) it('should sign rfqv1 order for a ERC1271_EIP712 MMP contract', async () => { - const marketMakingInfo = getMarketMakingInfo() const [deployer] = await ethers.getSigners() const user = Wallet.createRandom() const userAddr = user.address.toLowerCase() @@ -201,6 +200,7 @@ describe('RFQV1 NewOrder', function () { const walletContract = await deployERC1271Wallet(allowSigner, deployer) expect(walletContract.address).is.not.null replaceMarketMakingAddress(chainId, walletContract.address, updaterStack) + const marketMakingInfo = getMarketMakingInfo() const order = await callNewOrder({ base: 'ETH', quote: 'USDT',